2011-08-30 56 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語句可能會多次執行。