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.AUTOGenerationType.SEQUENCEallocationSize = 1

插入一个实体时,应用程序执行次数增加 100% 查询(从一个插入查询仅增加到 2 个查询:选择 nextval,并插入查询) 批量插入时,如果 batch_size = 10,应用程序增加 10% 以上

我的问题是,是否有批量插入但不执行许多select nextval 查询?比如GenerationType.IDENTITY,不执行select nextval,只是批量插入,ID会在数据库中按顺序处理。

当我用GenerationType.SEQUENCEallocationSize=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吗?

HIbernate 批量插入或更新在 Spring Boot 中不起作用

springjpa的更新删除怎么做