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 раз больше времени, чем первый.
Его просто тормозит экстремально. Например, первый запрос занимает 10 минут, 2-й 20, 3-й 40 минут, а примерно через 6 часов 4-й запрос не завершен, и я остановил программу.
Если вы запускаете тот же запрос к исходной базе данных через какой-либо SQL-клиент (не используя scala или JDBC), будет ли он работать медленнее с каждой следующей страницей?
Хорошо, попробовал с PHP, и у меня такая же проблема. Одно и то же время запроса для одного и того же запроса на обоих языках. Так что это проблема с sql. Любая идея?
Это то, что я, хотя. Я считаю, что это проблема SQL Query. Order By с Limit на самом деле не работает быстро, насколько я помню из своего прошлого опыта. По сути, база данных должна выбрать все записи, затем отсортировать их по указанному полю, а затем вырезать страницу. Вместо этого вы можете попробовать добавочный подход, используя окно, например, some_id > last_seen_id. Last_seen_id — это состояние вашей программы. Хотя этот вопрос больше не вопрос Scala.


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