繁体   English   中英

Spring JPA - Hibernate: 批量插入执行过多 select nextval ('sequence')

[英]Spring JPA - Hibernate: Batch insert execute too much select nextval (‘sequence’)

现在我正在尝试提高我的 web 应用程序的性能,我使用 spring JPA 2.3.0- Hibernate 5.4.15.Final,Postgres 12 并通过@Transaction 管理事务。 web app部署在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执行30次select nextval ,3次批量插入查询。

一些统计数据:

  • 如果使用 GenerationType.IDENTITY

    • 保存(实体):
      • insert into... :执行一次
    • saveAll(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.SEQUENCE with allocationSize = 1

  • 当插入一个实体时,应用程序增加 100% 次执行查询(从一个插入查询仅增加到 2 个查询:select nextval,并插入查询)
  • 批量插入时,如果 batch_size = 10,应用程序增加超过 10%

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

当我使用GenerationType.SEQUENCEallocationSize=1 (GenerationType.AUTO)进行测试时,应用程序执行了过多的select nextval查询,我认为它甚至比 IDENTITY 策略更糟糕。 而且由于某些原因,我不想使用allocationSize ,它可能会导致在运行 insert query manual 或 migrate data 时或其他一些情况下出现重复的主键错误。

经过一些研究,我找到了一种获取序列值列表的方法:

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

您正在寻找的是用于 id 生成的HiLo 算法

对于从序列生成的每个 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;

我会说我在这一点上有一些经验。 我正在插入超过 128,000 条记录。 而我的目标是提高这样做的耗时。 我会尝试将案例总结如下:

  1. 该代码没有使用任何 persist() 或 save() 方法。 这些记录是在@Transactionl 方法退出时保存的

  2. 我正在使用 hibernate 下面的批量插入是配置 map 中的设置

    spring.jpa.properties.hibernate.jdbc.batch_size: "40" spring.jpa.properties.hibernate.order_inserts: "true" spring.jpa.properties.hibernate.order_updates: "true" spring.main.allow-bean-definition-overriding: "true"

  3. 我修改了实体 ID 配置中的分配大小,如下所示:

@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。这就是我目前想要了解的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM