Spring JPA - Hibernate:批量插入执行太多选择 nextval('sequence')
Posted
技术标签:
【中文标题】Spring JPA - Hibernate:批量插入执行太多选择 nextval(\'sequence\')【英文标题】:Spring JPA - Hibernate: Batch insert execute too much select nextval (‘sequence’)Spring JPA - Hibernate:批量插入执行太多选择 nextval('sequence') 【发布时间】:2020-09-26 23:03:29 【问题描述】:现在我正在尝试提高我的 Web 应用程序的性能,我使用 spring JPA 2.3.0- Hibernate 5.4.15.Final、Postgres 12 并通过 @Transaction 管理事务。 Web 应用部署在 aws beanstalk 上,同时运行多个实例,但数据库实例不可扩展。我使用 bigSerial 类型作为表的 ID。
例如,我有一个 STUDENTS 表,ID 是 bigSerial 和其他一些列。 使用时遇到问题
@GeneratedValue(strategy = GenerationType.IDENTITY)
, 保存实体列表时,Hibernate 无法批量插入。 我尝试使用
@GeneratedValue(strategy = GenerationType.AUTO, generator = "students_id_seq")
@SequenceGenerator(name = "students_id_seq", sequenceName = "students_id_seq")
hibernate.id.new_generator_mappings=false
hibernate.jdbc.batch_size=10
hibernate.order_inserts=true
hibernate.order_updates=true
hibernate.batch_versioned_data=true
似乎Hibernate可以批量插入,但问题是Hibernate多次执行select nextval ('students_id_seq')
。如果一个实体列表有30条,Hibernate执行select nextval
30次,批量插入查询3次。
一些统计数据:
如果使用 GenerationType.IDENTITY
保存(实体):insert into ...
:执行一次
全部保存(n 个实体)
insert into ...
:执行n次
如果使用 GenerationType.SEQUENCE/ GenerationType.AUTO
保存(实体):select nextval ('students_id_seq')
:执行一次
insert into ...
:执行一次
全部保存(n 个实体):
select nextval ('students_id_seq')
:执行n次
insert into ...
: 执行 n/batch_size 次
总之,如果使用GenerationType.AUTO
或GenerationType.SEQUENCE
和allocationSize = 1
:
我的问题是,是否有批量插入但不执行许多select nextval
查询?比如GenerationType.IDENTITY
,不执行select nextval
,只是批量插入,ID会在数据库中按顺序处理。
当我用GenerationType.SEQUENCE
和allocationSize=1
(GenerationType.AUTO)
进行测试时,应用程序执行了太多select nextval
查询,我认为它比IDENTITY策略还要糟糕。
并且由于某些原因,我不想使用allocationSize
,在运行插入查询手动或迁移数据或其他情况时可能会导致重复主键错误。
经过一番研究,我找到了一种获取序列值列表的方法:
select nextval ('students_id_seq') from generate_series(1,10);
我们可以用 entityList.size() 替换 10 或者批量插入时 entityList 中没有 ID 的实体数量,刚好够用,不要在 ID 之间造成太大的差距,但我没有确定是否支持 Hibernate,如果支持,请将文档分享给我以供参考。
谢谢
https://discourse.hibernate.org/t/batch-insert-execute-too-much-select-nextval-sequence/4232
【问题讨论】:
【参考方案1】:您正在寻找的是用于 id 生成的 HiLo algorithm。
对于从序列生成的每个 id,它会在客户端生成多个 id,而无需访问数据库。
你在你的实体上这样配置它:
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hilo_sequence_generator")
@GenericGenerator(
name = "hilo_sequence_generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters =
@Parameter(name = "sequence_name", value = "hilo_seqeunce"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "3"),
@Parameter(name = "optimizer", value = "hilo")
)
@Id
private Long id;
【讨论】:
用 mysql 和 spring boot 尝试过 hiLo,它仍然在 db 中创建一个序列并使用太多 select next_val 更新以上是关于Spring JPA - Hibernate:批量插入执行太多选择 nextval('sequence')的主要内容,如果未能解决你的问题,请参考以下文章
Spring Data JPA saveAll 不进行批量插入
spring jpa specification 怎么关联查询
Spring数据JPA存储库saveAll不生成批量插入查询
JPA的批量更新会触发TransactionalEventListener吗?