Ищете способ ускорить обновление данных с помощью Spring Data JPA - PullRequest
0 голосов
/ 25 февраля 2019

Коллеги, я хотел бы получить много советов по следующему случаю.

Наш проект основан на Spring Data JPA - следовательно, моя реализация репозитория основана на SimpleJpaRepository.

Метод, который будет обсуждатьсянаходится в службе, помеченной @ Transactional.
Насколько я понимаю, Spring создает Entity Manager, сбрасывает данные и фиксирует транзакции, если я не вмешиваюсь в процесс.

Проект читает и анализирует внешний json дважды.Первый запуск - JSON дается для заполнения таблицы.Второй запуск - json того же размера с некоторыми новыми значениями здесь и там, для обновления таблицы.

Таблица имеет УНИКАЛЬНЫЙ индекс в поле поиска, используемом для обновления.Объект данных является базовым без каких-либо отношений @OneToMany.

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

Для прогона create я использовал простой метод репозитория #save, который выбирает между #persist и #merge, и ничего более.Очевидно, он выбирает #persist в моем случае.По всей вероятности, данные сбрасываются и транзакция совершается Spring.Я включил опцию «generate_statistics», и там есть 1 сброс и число созданных сущностей, как и ожидалось

Как я пытался ускорить обновление:

Во-первых, для запуска обновления я нарезалданные, которые должны быть обработаны в коллекции (на самом деле те, которые очищаются на каждом конце обработки слайса) и называются сначала #saveAll, а затем #flush (что фактически является em # flush). Этот подход основан на этих обсуждениях Как повысить производительностьОбновление данных с использованием JPA и HIbernate commit () и flush ()

Увы, затраты времени были практически одинаковыми, количество операций JDBC было одинаковым, количество сбросовбыл как ожидалось (скажем, 29 сбросов, когда размер «пачки» был 1000, 2900 сбросов, когда размер «пачки» был 10).Странно, однако, что количество объектов на этот раз отличалось от количества записей в таблице, которые будут обновлены

Журнал выглядит как

76545093741 nanoseconds spent executing 2860 flushes (flushing a total of 40912292 entities and 0 collections);
756096912142 nanoseconds spent executing 28592 partial-flushes (flushing a total of 408736936 entities and 408736936 collections)

40912292 объектов?408736936 сущностей и коллекций?Но почему?Мне также интересно, что это за частичные приливы - что их вызывает?почему их число плавает?

Интересно, почему ручные периодические очистки не помогли.

Во-вторых, во время предыдущей попытки я использовал объект данных с первичным ключом, автоматически сгенерированный со стратегией IDENTITY.

На этот раз я решил попробовать пакетную обработку.Я изменил стратегию генерации PK на SEQUENCE и добавил набор свойств Spring для пакетной обработки:

jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 50
          batch_versioned_data: true
          order_inserts: true
          order_updates: true

Какой журнал я получил в этом случае:

250614501 nanoseconds spent preparing 28594 JDBC statements;
8759177291 nanoseconds spent executing 28592 JDBC statements;
3398281 nanoseconds spent executing 2 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
7925542816 nanoseconds spent executing 286 flushes (flushing a total of 4104092 entities and 0 collections);
794086157441 nanoseconds spent executing 28592 partial-flushes (flushing a total of 408736936 entities and 408736936 collections)

Так что только 2 пакета ..и практически без увеличения скорости

Очевидно, что что-то не так, может быть неправильно настроено.Можно как-нибудь это исправить?Есть ли способ увеличить скорость обновления?

И, наконец, ... и, возможно, самая важная попытка, которую я тестировал.

После создания-запуска, когда транзакция завершена, я думал, что сущность отсоединяется и должна быть объединена (утверждают, чтоздесь: Метод JPA commit () делает сущность отсоединенной? ) Я даже перезапустил Jetty.Единственное, что сделал мой код обновления, - это установил новое значение во время запуска обновления.Это новое значение было волшебным образом перенесено в БД без вызова метода репозитория saveAndFlash (т.е. entitymanager.merge) :) Увы, никакого увеличения скорости обработки, хотя ...

1 Ответ

0 голосов
/ 06 марта 2019

Поскольку никто не предлагал никакого решения, позвольте мне рассказать, что помогло мне в итоге

Я ввел в класс обслуживания следующее:

@PersistenceContext
private EntityManager entityManager;

и позвонил

entityManager.clear();

после каждых 1000 записей

...