Массивная вставка с JPA + Hibernate

Мне нужно сделать массивную вставку, используя EJB 3, Hibernate, Spring Data и Oracle. Первоначально я использую Spring Data и код ниже:

talaoAITDAO.save(taloes);

Где talaoAITDAO - это подкласс Spring Data JpaRepository, а taloes - это объект Collection TalaoAIT. В этом объекте его соответствующий идентификатор имеет такую ​​форму:

@Id
@Column(name = "ID_TALAO_AIT")
@SequenceGenerator(name = "SQ_TALAO_AIT", sequenceName = "SQ_TALAO_AIT", allocationSize = 1000)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_TALAO_AIT")
private Long id;

Также у этой сущности нет связанных сущностей для каскадной вставки.

Моя проблема здесь заключается в том, что все объекты вставляются по отдельности (например, INSERT INTO TABLE(col1, col2) VALUES (val1, val2)). Иногда это может вызвать тайм-аут, и все вставки будут отменены. Я хотел бы преобразовать эти отдельные вставки в пакетные вставки (такие как INSERT INTO TABLE(col1, col2) VALUES (val11, val12), (val21, val22), (val31, val32), ...).

Изучая альтернативы для повышения производительности, я нашел эту страницу в документации по Hibernate, за исключением путаницы в размерах пакетов Hibernate и этой другой странице. Основываясь на них, я написал этот код:

Session session = super.getEntityManager().unwrap(Session.class);
int batchSize = 1000;
for (int i = 0; i < taloes.size(); i++) {
    TalaoAIT talaoAIT = taloes.get(i);
    session.save(talaoAIT);
    if(i % batchSize == 0) {
        session.flush();
        session.clear();
    }
    taloes.add(talaoAIT);
}
session.flush();
session.clear();

Также в peristence.xml я добавил эти свойства:

<property name="hibernate.jdbc.batch_size" value="1000" />
<property name="order_inserts" value="true" />

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

Итак, мой вопрос: чего здесь не хватает? Некоторая конфигурация? Какой-то метод не используется?

Спасибо,

Рафаэль Афонсо.

3 ответа

Пара вещей.

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

Далее используйте EntityManager вместо того, чтобы делать все эти неприятные спящие вещи. EntityManager также имеет flush а также clear метод. Это должно по крайней мере очистить ваш метод. Без заказа это помогает немного очистить сеанс и предотвратить грязные проверки всех объектов в нем.

EntityManager em = getEntityManager();
int batchSize = 1000;
for (int i = 0; i < taloes.size(); i++) {
    TalaoAIT talaoAIT = taloes.get(i);
    em.persist(talaoAIT);
    if(i % batchSize == 0) {
        em.flush();
        em.clear();
    }
    taloes.add(talaoAIT);
}
em.flush();
em.clear();

Далее вам не следует делать свои пакеты слишком большими, так как это может вызвать проблемы с памятью, начните с чего-то вроде 50 и проверьте, что / что работает лучше всего. Есть момент, когда грязная проверка займет больше времени, чем очистка и очистка базы данных. Вы хотите найти это сладкое место.

Решение, опубликованное M. Deinum, отлично сработало для меня, при условии, что я установил следующие свойства Hibernate в своем JPA persistence.xml файл:

<property name="hibernate.jdbc.batch_size" value="50" />
<property name="hibernate.jdbc.batch_versioned_data" value="true" />
<property name="hibernate.order_inserts" value="true" />
<property name="hibernate.order_updates" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.connection.autocommit" value="false" />

Я использую базу данных Oracle, поэтому я также определил эту:

<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />

Недавно я нашел многообещающую небольшую библиотеку для пакетной вставки с Hibernate и Postgresql. Он называется pedal-dialect и использует команду Postgresql - COPY который, как утверждают многие, намного быстрее, чем пакетные вставки (ссылки: руководство Postgresql, стратегии вставки Postgresql - тест производительности, как работает копирование и почему оно намного быстрее вставки?). педаль-диалект позволяет использовать COPY без полной потери простоты использования Hibernate. Вы по-прежнему получаете автоматическое сопоставление сущностей и строк, и вам не нужно реализовывать его самостоятельно.

Другие вопросы по тегам