大多数 Hibernate 关联都支持“fetch”参数:
fetch="join|select"
“选择”是默认值。
如何决定将哪个用于哪个关联?
我尝试将所有应用程序范围从“选择”更改为“加入”——生成的查询数量可能减少了 10 倍,但性能保持不变(甚至变得更糟)。
谢谢。
加入应该解决n+1问题。如果您有 10 个父母,每个父母有 10 个孩子,则 join 将需要一个查询,而 select 将需要 11 个(父母一个,每个父母的孩子一个)。如果数据库与应用程序在同一台服务器上,或者网络非常快,这可能没什么大不了的,但如果每次数据库调用都有延迟,它就会累加。join 方法在初始查询上的效率稍低,因为您在每一行中复制父列,但您只对数据库进行一次往返。
一般来说,如果我知道我需要所有父母的孩子,我会加入。如果我只需要几个父母的孩子,我会使用 select。
Select 将通过向数据库发出新查询来获取子项。Join 将通过将子项连接到父项的查询中来获取子项。这就是为什么您会看到类似的性能,即使查询数量有所下降。
选择:
SELECT * FROM parent WHERE id=(whatever)
SELECT * FROM child WHERE id=(parent.child.id)
加入:
SELECT *
FROM parent
LEFT OUTER JOIN child ON parent.child.id=child.id
WHERE parent.id=(whatever)
至于何时使用一个而不是另一个......不完全确定。它可能取决于数据库系统。如果一个总是比另一个更好,我怀疑他们会费心给你选择!如果你看到每个都有相似的性能,我不会担心。
如果父母有很多孩子,而这些孩子又有很多其他孩子,那么在这种情况下,最初的“加入”可能会阻塞网络。我的建议是在这种情况下使用“选择”来拆分选择。
fetching="join" 如果您执行 fetching="join",它将在单个 select 语句中检索所有信息。
fetching="select" 如果你想使用第二个 select 语句来获取关联的集合,那么你将使用 fetch="select"。
来源:休眠获取策略
通常,出于性能原因,JOIN 是首选。
使用 SELECT 的一个原因是,如果您要对具有多对多关系的结果(设置偏移量和限制)进行分页。如果您使用 JOIN,如果根实体包含多个多对多子实体,并且这些“副本”会超出您的限制(即使 Hibernate 在使用 DISTINCT_ROOT_ENTITY 事实后将它们折叠),它将出现多次。
人们总是谈论使用fetch=JOIN对性能的影响。但我认为,了解我们正在获取的父/子记录的数量对我们来说很重要:
如果您只想获取单个 Parent 记录并期望它没有很多孩子,那么我建议您使用fetch=SELECT。
如果您想获取所有父记录,包括其子记录,那么最好使用fetch=JOIN
只是要补充一点,如果记录是懒惰地获取子项(lazy=true),那么使用fetch=JOIN没有任何意义,因为所有父项和子项记录都是一次性加载的。