我有父/子单向关系。当我检查日志时,我看到每个子行都有一个单独的插入查询,相当于让我们说:
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缓存的大小,因此耗尽内存不是问题。
答案 0 :(得分:3)
在单个查询中插入所有行实际上效率较低。
首先,有几点意见:
在幕后,Hibernate为您代表它执行的每个查询使用PreparedStatement
,这些查询被缓存并重用。 MySQL缓存“编译”SQL语句。在没有陷入细节的情况下,底层技术经过高度优化,可以多次运行相对较少的查询。
如果将insert作为单个语句执行,那么每次要插入的值的数量不同时,必须编译和缓存新的SQL(可能从缓存中推送另一个查询),这会增加开销。每次只使用相同的SQL时,可以避免这种开销。
由于许多原因,您必须在SQL中使用绑定变量,Hibernate将自动为您执行此操作。如果你做一些自定义查询来测试一次性插入方法,你肯定也应该使用绑定变量。
另一个考虑因素是如何生成标识符。如果它是通过数据库中的标识列,那么Hibernate需要接收每列的ID,这通常只有在创建一行时才可以。出于这个原因,基于序列的标识符生成器是效率的首选,客户端缓存序列值。
我刚注意到你的编辑:我的经验是Hibernate在处理插入父子数据时会做“额外”更新。我设法通过将映射更改为具有“连接”表(就像您将看到的多对多关系)来获得“纯”插入,即使我只有多对一的关系。就我而言,在三个表中进行大量插入操作要快得多,而插入更少,并且更新到两个表中。如果你担心性能,你肯定应该计划一段时间来调整Hibernate配置。