Обработка большого количества данных из PostgreSQL - PullRequest
0 голосов
/ 25 февраля 2019

Я ищу способ обработки большого объема данных, которые загружаются из базы данных в разумные сроки.

Проблема, с которой я сталкиваюсь, заключается в том, что мне нужно прочитать все данные избазы данных (в настоящее время около 30M строк), а затем обработать их на Java.Сама обработка не является проблемой, но получение данных из базы данных.Получение обычно занимает от 1-2 минут.Однако мне нужно, чтобы это было намного быстрее, чем это.Я загружаю данные из базы данных в DTO, используя следующий запрос:

select id, id_post, id_comment, col_a, col_b from post_comment

Где id - первичный ключ, id_post и id_comment - внешние ключи для соответствующих таблиц, а col_a и col_b - это столбцы с небольшими типами данных int.Столбцы с внешними ключами имеют индексы.В настоящее время я использую следующие инструменты: Java, Spring Boot, Hibernate и PostgreSQL.

До сих пор мне приходилось выбирать только следующие варианты:

  1. Спящий режим Ditch для этого запроса.и попробуйте использовать обычное соединение jdbc, надеясь, что оно будет быстрее.
  2. Полностью переписать алгоритм обработки с Java на процедуру SQL.

Я что-то пропустил или это мои единственные варианты?Я открыт для любых идей.Обратите внимание, что мне нужно только прочитать данные, но не изменять их.

РЕДАКТИРОВАТЬ: Объяснить анализ используемого запроса

"Seq Scan on post_comment (cost=0.00..397818.16 rows=21809216 width=28) (actual time=0.044..6287.066 rows=21812469 loops=1), Planning Time: 0.124 ms, Execution Time: 8237.090 ms"

Ответы [ 4 ]

0 голосов
/ 26 февраля 2019

Поскольку вы спрашивали об идеях, я видел, как эта проблема решается в следующих вариантах в зависимости от того, как она вписывается в вашу среду: 1) Сначала попробуйте с JDBC и Java, простым кодом, и вы можете выполнить тестовый прогон в вашей базе данных иДанные, чтобы увидеть, достаточно ли этого улучшения.Здесь вам нужно будет пойти на компромисс с другими преимуществами Hibernate.2) В пункте 1 используйте многопоточность с несколькими соединениями, перетаскивая данные в одну очередь, а затем вы можете использовать эту очередь для дальнейшей обработки или печати по мере необходимости.Вы можете также рассмотреть Кафку.3) Если данные будут продолжать расти, вы можете рассматривать Spark как новейшую технологию, которая может сделать все это в памяти и будет намного быстрее.

Это некоторые из вариантов, пожалуйста, если ониидеи помогут вам где угодно.

0 голосов
/ 26 февраля 2019

Вам нужно обрабатывать все строки одновременно или вы можете обрабатывать их по одной за раз?

Если вы можете обрабатывать их по одной за раз, попробуйте использовать прокручиваемый набор результатов.

org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);

while(sr.next())
{
    MyClass myObject = (MyClass)sr.get()[0];
    ... process row for myObject ... 
}

Это будет все еще запоминать каждый объект в менеджере сущностей, и поэтому будет становиться все медленнее и медленнее.Чтобы избежать этой проблемы, вы можете отсоединить объект от менеджера сущностей после того, как закончите.Это можно сделать только если объекты не изменены.Если они будут изменены, изменения НЕ будут сохранены.

org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);

while(sr.next())
{
    MyClass myObject = (MyClass)sr.get()[0];
    ... process row for myObject ... 
    entityManager.detach(myObject);
}
0 голосов
/ 26 февраля 2019

Если бы я был на вашем месте, я бы определенно обошел спящий режим и отправился бы напрямую в JDBC для этого запроса.Hibernate не предназначен для работы с большими наборами результатов и представляет дополнительные издержки для преимуществ, которые не применимы к подобным случаям.

Когда вы используете JDBC, не забудьте установить для autocommit значение false и установить какой-то большой размер выборки (порядка тысяч), иначе postgres сначала извлечет все 21 миллион строк в память, прежде чем начать выдавать ихвы.(См. https://stackoverflow.com/a/10959288/773113)

0 голосов
/ 25 февраля 2019

Почему 30М хранится в памяти ??лучше переписать его на чистый sql и использовать нумерацию страниц на основе идентификатора

, вам будет отправлено 5 в качестве идентификатора последнего комментария, и вы выдадите

select id, id_post, id_comment, col_a, col_b from post_comment where id > 5 limit 20

, если вам нужно обновитьвсю таблицу, то вам нужно поместить задачу в cron, но и там, чтобы обрабатывать ее по частям, память дороги и загрузка 30M очень дороги - вам нужно обрабатывать детали 0-20 20-n n + 20

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...