JDBC становится очень медленным после нескольких больших sql-выборов в scala

atm я пытаюсь получить много данных (26 миллионов записей) из базы данных sql, чтобы поместить их в LevelDB.

Я использую scala и пул соединений из JDBC. Это мой запрос:

"SELECT ts.block_id, ts.sender, ts.fee, ts.recipient AS transaction_recipient, ts.amount AS transaction_amount, ts.type, tf.recipient AS transfer_recipient, tf.amount AS transfer_amount FROM transactions ts LEFT OUTER JOIN transfers tf ON (tf.transaction_id = ts.transaction_id) ORDER BY ts.block_id ASC LIMIT " + (x*sqlBatchSize) + ","+sqlBatchSize)

Где sqlbatchSize — это параметр, указывающий, сколько записей я хочу получить в одном выражении SQL, а x — количество итераций. Поэтому просто я прошу выбрать **** Limit 0,10.000, затем 10.000,10.000, а затем 20.000,10.000 и так далее. Пробовал разные размеры от 5к до 10к, 100к, 500к, 5ккк и так далее. Пробовал с некоторым начальным значением, поэтому я получаю записи только из последней половины базы данных и тому подобное. У меня всегда одна и та же проблема. Первый запрос быстрый, второй медленнее, а затем следующие медленнее и медленнее. Неважно, если я запрошу 10x 10k или 10x 500k записей. Всегда одно и то же.

Вот мой код, немного укороченный:

import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import java.sql.{Connection, DriverManager}
import org.apache.commons.dbcp2._
import com.google.common.primitives.Longs
import com.typesafe.config._
import scala.math.BigInt
import java.io.File
import java.util.Calendar
import org.iq80.leveldb
import org.iq80.leveldb.impl.Iq80DBFactory._
import org.iq80.leveldb.Options
object Datasource {
  // Load config
  val conf = ConfigFactory.load()
  val dbUrl = "jdbc:mysql://" + conf.getString("database.db_host") + ":" + conf.getString("database.db_port") + "/" + conf.getString("database.db_name")
  val connectionPool = new BasicDataSource()
  connectionPool.setUsername(conf.getString("database.db_user"))
  connectionPool.setPassword(conf.getString("database.db_password"))
  connectionPool.setDriverClassName("com.mysql.jdbc.Driver")
  connectionPool.setUrl(dbUrl)
  connectionPool.setInitialSize(3)
}
object main extends App {
  var durchlaufen = 1
  var x = 0
  var sqlBatchSize = 50000
  if (durchlaufen == 1){
    try{
      var grenze = 10
      while(x < grenze) {
        val connection = Datasource.connectionPool.getConnection
        val rs = connection.createStatement.executeQuery("SELECT ts.block_id, ts.sender, ts.fee, ts.recipient AS transaction_recipient, ts.amount AS transaction_amount, ts.type, tf.recipient AS transfer_recipient, tf.amount AS transfer_amount FROM transactions ts LEFT OUTER JOIN transfers tf ON (tf.transaction_id = ts.transaction_id) ORDER BY ts.block_id ASC  LIMIT " + (x*sqlBatchSize+10000000) + ","+sqlBatchSize)
        x += 1
        while (rs.next()) {
          // Do stuff
        }
        connection.close()
        rs.close()
      }
    } 
  }
}

Что я тоже пробовал, так это закрыть соединение и работать с одним и тем же соединением во всех итерациях. Тот же результат

Я проверил с помощью visualVm память, и есть один массив байтов, который очень велик и максимально использует оперативную память. Но я понятия не имею, что это за байтовый массив

Кто-нибудь знает, почему запросы начинают работать очень медленно?

Если это так, я запрашиваю 10x 500k записей, тогда оперативная память заполнена, и она будет замедляться, хорошо. Я могу понять, что. Но если я запрашиваю 10x 5k, он идет медленно с той же скоростью, что и 10x 500k, только один запрос занимает больше времени. В конце концов, третий запрос занимает примерно вдвое больше времени, а седьмой запрос занимает примерно в 6-9 раз больше времени, чем первый.

Вы в конечном итоге получили OutOfMemoryError и сбой JVM? Или ваше приложение продолжает работать, но медленно?

Alexey Novakov 24.02.2019 20:23

Его просто тормозит экстремально. Например, первый запрос занимает 10 минут, 2-й 20, 3-й 40 минут, а примерно через 6 часов 4-й запрос не завершен, и я остановил программу.

Introser 24.02.2019 21:55

Если вы запускаете тот же запрос к исходной базе данных через какой-либо SQL-клиент (не используя scala или JDBC), будет ли он работать медленнее с каждой следующей страницей?

Alexey Novakov 25.02.2019 08:37

Хорошо, попробовал с PHP, и у меня такая же проблема. Одно и то же время запроса для одного и того же запроса на обоих языках. Так что это проблема с sql. Любая идея?

Introser 25.02.2019 13:52

Это то, что я, хотя. Я считаю, что это проблема SQL Query. Order By с Limit на самом деле не работает быстро, насколько я помню из своего прошлого опыта. По сути, база данных должна выбрать все записи, затем отсортировать их по указанному полю, а затем вырезать страницу. Вместо этого вы можете попробовать добавочный подход, используя окно, например, some_id > last_seen_id. Last_seen_id — это состояние вашей программы. Хотя этот вопрос больше не вопрос Scala.

Alexey Novakov 26.02.2019 11:47
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
5
71
0

Другие вопросы по теме