【问题标题】:Why is batch inserting data with Hibernate on Oracle much slower with a larger transaction?为什么使用较大的事务在 Oracle 上使用 Hibernate 批量插入数据要慢得多?
【发布时间】:2018-08-16 15:18:18
【问题描述】:

我当前的项目包括一个归档功能,其中将内存数据库中的数据传输到关系数据库。

我从内存数据库中流式传输结果,创建休眠实体并将数据以 5000 个批次保存到数据库中。这些实体有几个关系,因此我将每个实体写入不同的表。

作为参考,您可以假设在整个归档过程中执行了 100 万次插入查询。

一开始这个过程真的很慢,于是上网查了一下,实现了一些用Hibernate批量写的常用建议:

  • 我将 hibernate.jdbc.batch_size 设置为合适的大小,并将 hibernate.order_inserts 设置为 true。
  • 为防止出现内存问题,我不时刷新并清除休眠会话。

这是一个批处理的小例子:

RedisServiceImpl.Cursor<Contract> ctrCursor = contractAccessService.getCursor("*", taskId);

Iterators.partition(ctrCursor, BATCH_SIZE).forEachRemaining(chunk -> {

    portfolioChunkSaver.saveContractChunk(chunk, taskId);

    em.flush();
    em.clear();
});

ctrCursor.close();

此过程有效,但速度非常慢。在 Oracle 中插入 100 万条记录大约需要 2 个小时才能完成,即每秒约 2.5 次查询。

目前,整个归档功能都包含在 1 个事务中,这感觉完全不对。最大的好处是您可以确定存档是否成功完成,而无需为此提供一些额外的检查系统。 (一切要么在数据库中,要么不在)

作为加速实验,我修改了代码,为每个实体块 (5000) 创建一个数据库事务,而不是将所有内容包装在一个大事务中。

这种变化产生了巨大的影响,现在的速度大约是以前的 10-15 倍。

在进行分析时,我在更改之前看到了这种行为:

Before: 
Java - very low CPU
Oracle - very high CPU, low disk write activity

After:
Java - high CPU
Oracle - Low CPU, very high disk write activity

第二个行为很有意义,java 发送尽可能多的查询,而数据库服务器受到本地系统上写入磁盘速度的限制。

我的问题来了:为什么影响如此之大?当我在更大的事务中发送所有内容时,Oracle 有什么不同?

附带说明:我从来没有遇到过 MySQL 的这个问题,所以 Oracle(或 oracle JDBC 驱动程序)必须以不同的方式做某事。

我可以想象保证 ACID 合规性会导致开销,但我没想到会出现如此巨大的速度差异。

【问题讨论】:

    标签: java oracle hibernate


    【解决方案1】:

    您应该确保有足够的 UNDO 空间(也称为 UNDO 段),因为大型事务会消耗大量空间。

    当 ROLLBACK 语句发出时,撤消记录用于撤消 未提交的事务对数据库所做的更改。

    最好只在完成数据完整性之后才提交,并且经过适当调整的 Oracle 数据库可以支持大型事务而不会出现任何性能问题。

    【讨论】:

      猜你喜欢
      • 2017-10-22
      • 2015-07-03
      • 2016-05-22
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 2015-11-23
      相关资源
      最近更新 更多