Hibernate子查询 vs 批量获取

15

Hibernate提供(至少)两种解决N+1查询问题的方法。一种是将FetchMode设置为Subselect,它生成一个带有IN子句和嵌套在该IN子句中的子选择的select语句。另一种是指定BatchSize,它生成一个带有包含父项ID的IN子句的select语句。

这两种方法都可以工作,但我发现Subselect选项经常由于父查询的复杂性而遇到性能问题。另一方面,如果批处理大小很大(比如1000),则查询数量和查询复杂度非常小。

因此,我的问题是:在什么情况下会使用Hibernate的Subselect FetchMode而不是BatchSize?如果你有大量的父级条目(数千个),那么Subselect可能是有意义的,但是否有其他场景你会更喜欢使用Subselect而不是BatchSize呢?

编辑:我注意到两者处理急加载时存在差异。如果将xToMany关联设置为急加载并通过Subselect进行加载,则生成的Subselect与懒加载时生成的Subselect类似。然而,如果您指定BatchSize,则生成的查询将使用外部连接而不是单独的查询。是否有任何方法强制Hibernate在进行急加载时使用单独的批处理查询呢?

2个回答

14

我不使用子查询,因为很难控制。在一个非常庞大的系统中,有复杂的业务逻辑和大量的团队参与,很难说哪些查询会被使用。子查询可能在某些特定情况下起作用,你需要确切知道执行哪个查询。

批量获取有一些重要优点。虽然它并不总是最快的,但通常足够快。另一方面,它非常稳定,没有任何副作用,并且完全透明于业务逻辑。我从不使用高于100的批量值。这足以将N+1减少到一定合理数量的查询。


3
我不理解为什么子查询难以控制。你能否解释一下? - James Selvakumar
子查询取决于之前执行的查询。这个查询可能非常复杂,例如使用许多其他表并通过非索引列进行过滤。因此很难说子查询方法是否有助于提高性能。 - Stefan Steinegger
1
子查询在MySQL中可能会出现另一个问题;MySQL(5.5及以下版本)在嵌套查询方面性能差劲,因为它强制将它们关联起来,并且对父查询中的每一行重新评估它们。我找不到Hibernate为注释关系生成嵌套查询的其他方法,因此避免使用子查询将防止在MySQL中出现令人讨厌的意外。 - Barry Kelly

2
我发现这篇文章很有帮助。我相信批量获取可以应用于集合和父级,而子选择只能应用于集合。
在集合的获取策略中,子选择将执行一次(因为批处理大小实际上是无限的),而使用批量获取时,SQL语句可能会执行多次。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接