2011-08-30 96 views
13

Hibernate提供(至少)两种选项来解决N + 1查询问题。一个是将FetchMode设置为Subselect,它在此IN子句内生成一个带有IN子句和子选择符的select。另一个是指定一个BatchSize,它会生成一个带有包含父母ID的IN子句的select。休眠子选择与批量获取

这两个工作,但我发现子选择选项经常遇到性能问题,因为父母的查询是复杂的。另一方面,使用大的BatchSize(例如1000)时,查询的数量和这些查询的复杂度非常小。

我的问题是:何时使用Hibernate的Subselect FetchMode而不是BatchSize?如果您有大量父条目(数千个),则子选择可能是有意义的,但是在其他情况下,您希望将Subselect指定为BatchSize吗?

编辑:我注意到两个处理急切加载时的区别。如果您将xToMany关联设置为热切加载并通过子查询,则会生成一个类似于懒惰的子查询。但是,如果指定了BatchSize,则生成的查询将使用外部联接而不是单独的查询。有什么办法迫使Hibernate在加载时急切地使用单独的批处理查询?

回答

13

我不使用子选择,因为它很难控制。在一个拥有复杂业务逻辑和庞大团队的大型系统中,很难说哪些查询被使用。子选择可以在您确切知道执行哪个查询的特定情况下工作。

批量提取有一些很大的优势。它并不总是最快的,但通常足够快。另一方面,它非常稳定,没有任何副作用,并且对业务逻辑完全透明。我从来没有使用高于100的批量值。将N + 1减少到合理数量的查询就足够了。

+2

我不明白为什么子选择难以控制。你能抛出一些光吗? –

+0

子选择取决于之前执行的查询。该查询可能非常复杂,例如使用大量其他表格并通过非索引列进行筛选。因此很难说子查询方法是否可能提高性能。 –

+1

与sublectlect的另一个问题可以突然与MySQL; MySQL(5.5及以下版本)在嵌套查询方面表现糟糕,因为它强制使它们相互关联,并对父查询中的每一行重新评估它们。我无法找到任何其他方式让Hibernate为注释关系生成嵌套查询,因此避免使用子选择会防止MySQL出现令人讨厌的意外。 –

2

我发现this article会有帮助。我认为批次提取可以应用于集合和父级,而子选择只能应用于集合。

对于集合的获取策略,子查询将被执行一次(因为批量大小实际上是无穷大),而批量获取SQL语句可能会多次执行。