【发布时间】: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:
- 插入一个实体时,应用程序执行次数增加 100% 查询(从一个插入查询仅增加到 2 个查询:选择 nextval,并插入查询)
- 批量插入时,如果 batch_size = 10,应用程序增加 10% 以上
我的问题是,是否有批量插入但不执行许多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
【问题讨论】:
标签: java spring hibernate spring-data-jpa batch-insert