Подтвердить что ты не робот

Самый быстрый способ перебора больших таблиц с помощью JDBC

Я пытаюсь создать java-программу для очистки и объединения строк в моей таблице. Стол большой, около 500 тыс. Строк, и мое текущее решение работает очень медленно. Первое, что я хочу сделать, это просто получить массив массивов в памяти, представляющий все строки моей таблицы. Вот что я делаю:

  • выберите шаг 1000 строк за раз
  • используйте JDBC для извлечения набора результатов в следующем SQL-запросе SELECT * FROM TABLE WHERE ID > 0 AND ID < 1000
  • добавить полученные данные в массив в памяти
  • продолжить запрос до 500 000 с шагом 1000 при каждом добавлении результатов.

Это длится долго. Фактически, он даже не прошел второй шаг от 1000 до 2000. Запрос длится бесконечно (хотя, когда я запускаю одно и то же непосредственно через браузер MySQL, он прилично быстро). С тех пор я использовал JDBC напрямую. Есть ли более быстрая альтернатива?

4b9b3361

Ответ 1

Прежде всего, вы уверены, что вам нужна целая таблица в памяти? Возможно, вам следует рассмотреть (если возможно) выбор строк, которые вы хотите обновить/слить/и т.д. Если вам действительно нужно иметь всю таблицу, вы можете использовать прокручиваемый ResultSet. Вы можете создать его так.

// make sure autocommit is off (postgres)
con.setAutoCommit(false);

Statement stmt = con.createStatement(
                   ResultSet.TYPE_SCROLL_INSENSITIVE, //or ResultSet.TYPE_FORWARD_ONLY
                   ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery("select * from ...");

Он позволяет вам перемещаться в любую строку, которую вы хотите, используя методы "абсолютный" и "относительный".

Ответ 2

Хотя это, вероятно, не оптимально, ваше решение кажется, что оно должно быть хорошо для одноразовой процедуры очистки базы данных. Это не должно занять столько времени, чтобы выполнить такой запрос и получить результаты (я предполагаю, что с тех пор, как он пройдет через пару секунд, все будет хорошо). Возможные проблемы -

  • Ваша сеть (или, по крайней мере, ваше соединение с mysql) очень медленная? Вы можете попробовать запустить процесс локально в поле mysql, если это так, или что-то лучше связанное.

  • есть ли что-то в структуре таблицы, которая вызывает его? сбрасывая 10 тыс. данных для каждой строки? 200 полей? вычисление значений id для получения на основе неиндексированной строки? Вы можете попробовать найти более удобный для db способ вытащить данные (например, только нужные столбцы, иметь значения агрегата db и т.д.).

Если вы не получаете второе приращение, что-то действительно не так - эффективно или нет, у вас не должно быть проблем с демпингом 2000 или 20 000 строк в памяти на запущенной JVM. Возможно, вы сохраняете данные избыточно или крайне неэффективно?

Ответ 3

Одна вещь, которая помогла мне, была Statement.setFetchSize(Integer.MIN_VALUE). Я получил эту идею от Jason blog. Это сократило время выполнения более чем на половину. Потребление памяти резко сократилось (поскольку одновременно считывается только одна строка.)

Этот трюк не работает для PreparedStatement.