在 JPA 中插入多行的最有效方法

Posted

技术标签:

【中文标题】在 JPA 中插入多行的最有效方法【英文标题】:Most efficient way to insert multiple rows in JPA 【发布时间】:2016-03-04 14:59:46 【问题描述】:

我有一个父/子单向关系。当我检查日志时,我发现每个子行都有一个单独的插入查询,相当于假设:

insert into childTable(col1, col2) values(val1, val2);
insert into childTable(col1, col2) values(val3, val4);

在单个查询中插入所有行不是更有效吗?大致如下:

insert into childTable(col1, col2) values(val1, val2), (val3, val4)

有没有办法强制 JPA 生成多行插入而不是单行插入?

编辑: 我目前正在使用级联插入,所以我插入父级,子级的插入是自动生成的。我宁愿继续使用这种方法,而不是手动创建一个巨大的 SQL 查询,因为我认为级联插入会产生更清晰的代码。

我已经定期刷新会话以控制 L1 缓存的大小,因此内存不足不是问题。

【问题讨论】:

【参考方案1】:

在单个查询中插入所有行实际上效率较低。

首先,有几点观察:

    从客户端传递到服务器的数据量与一个或多个插入语句相同,其中“数据量”表示您存储的实际值。 Hibernate 支持请求批处理,因此客户端和服务器之间的往返次数可以与一个或多个插入语句大致相同。

在幕后,Hibernate 对它代表您执行的每个查询使用PreparedStatement,这些查询被缓存和重用。 mysql 缓存“编​​译”SQL 语句。无需深陷细节,底层技术经过高度优化,可多次运行相对较少的查询。

如果您将插入作为单个语句执行,则每次插入的值数量不同时,都必须编译和缓存新 SQL(可能从缓存中推送另一个查询),这会增加开销。当您每次只使用相同的 SQL 时,就可以避免这种开销。

出于多种原因,您必须在 SQL 中使用绑定变量,而 Hibernate 会自动为您执行此操作。如果您执行一些自定义查询来测试一次性插入方法,那么您肯定也应该使用绑定变量。

另一个考虑因素是如何生成标识符。如果是通过数据库中的标识列,那么 Hibernate 需要接收回每一列的 ID,这通常只有在创建一行时才有可能。出于这个原因,为了提高效率,优先使用基于序列的标识符生成器,​​并在客户端缓存序列值。

我刚刚注意到您的编辑:我的经验是 Hibernate 在处理插入父子数据时会进行“额外”更新。即使我只有多对一的关系,我也设法通过将映射更改为具有“连接”表(就像您会看到的多对多关系)来获得“纯”插入。就我而言,在三个表中执行更多插入操作要快得多,而对两个表执行更少的插入操作和更新要快得多。如果您担心性能,您绝对应该计划一些时间来调整 Hibernate 配置。

【讨论】:

这很有帮助。我很确定多行插入并没有明显更好,但我想我可能会通过只遍历底层 B 树一次来获得一些改进。我正在使用自动递增主键,但会考虑使用序列。 @ventsyv & Rob 我知道我讨论晚了,但请查看this 退出 @AbhishekBhatia 您链接到的问题是关于多值插入与单独的单值插入。这个问题是在hibernate的上下文中,它支持批量插入。批处理将在一次往返服务器中插入许多行,并为所有单独的插入重用已解析的语句。如果您不清楚这种区别,我建议您创建一个新问题:参考这两个问题并询问为什么答案似乎相互矛盾。

以上是关于在 JPA 中插入多行的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

在NodeJS中将许多文件中的JSON对象插入MongoDB的最有效方法

将元素插入到有序向量中的最有效方法是什么?

使用 Core Data 插入/更新记录的最有效方法?

执行 Mysql 多选的最有效方法(如果不存在则插入)

将数千条记录插入表中的最有效方法是啥(MySQL,Python,Django)

在 .NET 中编写大型多步骤表单的最有效方法是啥?