Spring 使用 GenerationType.IDENTITY 时,批处理 JPA 批量插入会消耗性能

Spring Batch JPA Bulk Insert eats performance when using GenerationType.IDENTITY

我正在使用 Spring Boot and Spring Batch and JPA 将数据从一个数据库加载到另一个数据库。在单个批处理作业中,我按顺序创建了 10 steps 到 运行 个步骤,每个步骤几乎读取 1 millions 个记录(我不能 运行 并行,因为数据我没有并行加载)。

我用过 GenerationType.IDENTITY 并且看起来像因为这个批处理作业占用了大量时间。如果我说要加载 100 records,它需要 2 min。目标 Postgres database 已由 DBA 实现 sequences,我们必须遵循这些目标,但它耗尽了所有性能。

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "EMP_ID", nullable = false, updatable = false, insertable = false)
private Long id;

我怎样才能提高这个批处理作业的性能?

我也保留了 spring.jpa.properties.hibernate.jdbc.batch_size=1000chunkSize=1000

我杰夫

去年,我和我的团队遇到了这样一种情况,即一项工作要花很长时间才能执行数据库写入操作。

我们为提高性能所做的工作是:

  • 仅将存储库和托管实体用于数据库读取操作,但切勿更改这些实体,以避免 spring jpa 将更改写入数据库。
  • 为 insert/update 操作创建存储过程。
  • 使用索引参数通过 JDBCBatchItemWriter 调用 SP
  • 使用 ItemPreparedStatementSetter 设置参数

这样我们可以提高性能,减少数据库调用!

希望对您有所帮助

如果实体使用 IDENTITY 生成其 ID,Hibernate 无法批量插入实体(在 here 的文档中也提到)。

所以你必须改为使用SEQUENCE来生成ID。并根据 this ,选择使用“pooled”或“pooled-lo”算法从序列中获取新 ID,以通过减少获取 ID 的往返次数来进一步提高性能。

因此 ID 映射如下所示:

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="emp_sequence")
@SequenceGenerator(name="emp_sequence", sequenceName = "emp_id_seq", allocationSize = 100)
private Long id;

以及休眠设置:

spring.jpa.properties.hibernate.order_inserts = true
spring.jpa.properties.hibernate.order_updates = true
spring.jpa.properties.hibernate.jdbc.batch_size = 1000
spring.jpa.properties.hibernate.jdbc.batch_versioned_data = true


# For using "pool-lo" optimiser for generating ID when using JPA @SequenceGenerator
spring.jpa.properties.hibernate.id.optimizer.pooled.preferred = pooled-lo

另外,你必须确保PostreSQL中对应的ID序列与@SequenceGenerator中的配置对齐:

alter sequence emp_id_seq increment by 100;

另一个技巧是在 JDBC 连接字符串中添加 reWriteBatchedInserts=true,如 docs.

所述,这将提供 2-3 倍的性能提升