azerphoenix
@azerphoenix
Java Software Engineer

Как ускорить процесс получения большого объема данных?

Доброго времени суток!
Задача вкратце - есть 1-й datasource (View), изкоторого нужно получить данные и записать их во второй datasource. После получения данных из 1-й БД необходимо для каждого адреса получить координаты из nominatim (поднят, как отдельный сервис).
Логика работы - запрос приходит из фронта, запускается процесс обновления данных и записывается в БД. Потом на фронт возвращается deferredResult со статусом "ок" и компонент таблицы отрисовывается с новыми данными.
Кол-во данных за 1 раз до 10 000.

Что реализовано на данный момент -
Получаю Stream<T> по 1000 из первой БД, итерирую по нему и получаю координаты и записываю их в БД (разумеется, там есть проверки, валидации и т.д.). В общей сложности для 10 000 данных весь процесс занимает около 20-25 мин. Если стрим записи в БД сделать параллельным (parallelStream()), то появляется проблема при записи в БД, так как некоторые потоки пытаются одновременно обновить одни и те же данные. Но если в целом ошибок не возникает, то время сокращается дважды.
Разумеется, что не хочется заставлять юзера так долго ждать. + к тому же если он обновит страницу, то данные могут быть не обновлены.

Что раньше пытался реализовать - использовать Spring Quartz и на запрос юзера возвращать uuid, по которому фронт будет дергать статус и если все ок, то рендерить компонент. Правда, возникли некоторые проблемы с самим фреймворком.

Вариант с дерганием данных по CRON, не является решением. Хоть и реализован на данный момент тоже. Т.е. пользователь всегда может захотеть получить актуальные данные.
  • Вопрос задан
  • 238 просмотров
Решения вопроса 4
@rPman
что именно занимает так много времени, проведи профилирование чтобы выяснить где больше всего проводит времени твой код - например внутренняя обработка данных или база данных?
для 10 000 данных весь процесс занимает около 20-25 мин.
для такого объема записей это слишком большой срок для базы данных

Что за анализ выполняется для этих данных что так медленно? почти наверняка это сделано ОЧЕНЬ не эффективно, особенно если вылезает вот это:
Если стрим записи в БД сделать параллельным (parallelStream()), то появляется проблема при записи в БД, так как некоторые потоки пытаются одновременно обновить одни и те же данные.

получается что для каждой единицы данных ты проводишь анализ в базе, совершаешь действия для этой записи и переходишь к следующей, логично что если в такой схеме делать это параллельно, порядок нарушается и если результат одной задачи будет зависеть от другой - можно получить 'поврежденные' данные

Правильно - разделить свою задачу на три - анализ, обработка и сохранение данных. Затем анализ и/или обработку переделать на работу с одновременно большим количеством данных.. в оперативной памяти, а уже потом записать результат.

Классический пример: для каждой записи ты делаешь запрос - найти соответствующий объект(ы) в базе, прочитать их, изменить и записать результат в базе. нужно сделать так - выгрузить сразу много записей (условно по 1000), изменить их с учетом того что это будет происходить в оперативной памяти, многократная запись одних и тех же объектов не будет занимать столько времени как запись в базу.

Возможно у тебя этап загрузки из базы уже часть анализа, возможно придется переделать запрос с учетом того что он работает с большим количеством объектов, может даже больше информации выгружать.

Современные даже десктопные машины с 16-32гб (а серверные с 128-256 легко) оперативной памяти позволяют вообще зхагрузить большую часть данных в оперативную память и обработать ее там эффективнее чем это получится делать через sql прослойку, которая рассчитана не на скорость обработки а на надежность хранения и многопользовательский доступ.
Ответ написан
compilator
@compilator
Senior Data Engineer
Сходу - это выглядит как обычная батчевая обработка данный. Легко реализуется с помощью spark.
Ответ написан
mayton2019
@mayton2019 Куратор тега Java
Bigdata Engineer
Сложно обсуждать перформанс-проблему без исходного кода.

Я-бы предложил как всегда ударить кувалдой. Тоесть запустить по приложению JProfiler и просто посмотреть что он покажет. Проблемных мест может быть 3. Это чтение из базы. Второе это собственно проверки и валидации. Как они реализованы? Насколько качественно? И третье это собсно запись в БД. Используется ли JDBC-batch?

SpringQuartz, cron, view здесь вообще непричем и их наличие только путает нас и вносит новые ненужные вопросы. Лучше решать проблему как одну java-функцию с входом и выходом.
Ответ написан
azerphoenix
@azerphoenix Автор вопроса, куратор тега Java
Java Software Engineer
Проблему решил путем применения Spring Batch.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы