spring-data-jpa Spring JPA -休眠:批插入执行过多的select nextval('sequence')

nom7f22z  于 2022-11-10  发布在  Spring
关注(0)|答案(2)|浏览(147)

现在我尝试提高我的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次。
一些统计数据:

  • 如果使用生成类型.IDENTITY
  • 保存(实体):
  • insert into ...:执行一次
  • 全部保存(n个实体)
  • insert into ...:执行n次
  • 如果使用层代类型.序列/层代类型.自动
  • 保存(实体):
  • 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,它可能会导致在手动运行插入查询或迁移数据或其他情况下出现重复主键错误。
经过一番研究,我找到了一种获取序列的值列表的方法:
x1米20英寸
我们可以用entityList.size()代替10个或者在entityList中没有ID的实体的数量,当批量插入时,只要得到足够的ID就可以了,不要在ID之间造成太大的空隙,但是我不确定Hibernate是否支持,如果是的话,请把文档分享给我参考。
谢谢你
https://discourse.hibernate.org/t/batch-insert-execute-too-much-select-nextval-sequence/4232

pinkon5k

pinkon5k1#

您正在寻找的是用于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;
xu3bshqb

xu3bshqb2#

我想说的是,我在这一点上有一些经验。我正在为超过128,000条记录执行插入操作。我的目标是提高执行插入操作所需的时间。我将尝试将该案例总结如下:
1.代码未使用任何persist()或保存()方法。这些记录在@Transactionl方法退出时保存
1.我使用的是Hibernate批处理插入下面是配置图中的设置
批处理大小:“40”Spring.jpa.属性.休眠.订单_插页:“真”Spring.jpa.属性.休眠.订单更新:“true”spring.main.允许Bean定义覆盖:“真”
1.我修改了实体ID配置中的分配大小,如下所示:
@标识

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator ="mappingentry_sql_generator")

@SequenceGenerator(name = "mappingentry_sql_generator", sequenceName ="mappingentry_id_seq", allocationSize = 40)

private Long id;

注意:我将序列生成器中的“allocationSize”设置为等于设置中的“batch_size”值
1.此外,我还修改了序列“mappingentry_id_seq”,使其增量为40
在做了这些更改后,时间从55秒减少到20秒,这是一个很大的影响
我唯一不明白的是,当我检查由序列生成的id列的值时,我没有发现任何值差距。每个ID值都比前一个值大1,而不是40。这就是我目前试图理解的

相关问题