您的投影通常會在幾乎所有箱子出執行list().size()
方法調用。爲了理解爲什麼,我們需要強調兩種方法之間的差異。
當您要求Hibernate執行list().size()
時,會發生什麼情況?
- 我們向數據庫級別的目標表發出select。
- 數據庫必須從磁盤讀取數據頁面,將結果加載到內存中。這消耗了寶貴的數據庫服務器資源,如CPU週期,磁盤I/O和內存。
- 數據庫服務器必須將這些結果傳送到應用程序服務器。此過程受結果集的行數,寬度和網絡連接延遲影響很大。
- 實例化應用程序服務器上的集合元素,並將每個構造的實例添加到Hibernate Session的持久性上下文(1LC)中。這又會消耗內存和CPU週期來實例化和存儲這些對象。
- 如果您的集合元素包含任何熱切加載的關聯,那麼Hibernate將重複步驟1到4,直到基於獲取模式加載對象圖。顯然,當你所追求的是收集元素的數量時,這是完全不必要的。
- 要求JVM給你一個收集計數,次要但仍然浪費cpu週期。
當您讓Hibernate執行Projection.rowCount()
時,會發生什麼情況?
- 我們向數據庫級別的目標表發出投影查詢。
- 而不是數據庫需要從磁盤讀取數據頁面,如果您的projectin查詢只是基於主鍵和任何條件進行索引計數,查詢將快速返回,無論我們說的是小的還是行大表。
- 而不是將多個行和列的結果集流式傳輸迴應用程序服務器,所有返回的結果都是單一值 - 計數。這幾乎不消耗任何網絡帶寬。
- 由於我們返回一個值,Hibernate幾乎沒有努力返回該值。此外,由於它是一個總值,我們不會將任何信息放入會話的持久化上下文(1LC)中,所以在這裏沒有不必要的內存消耗。
- 由於我們沒有返回實體,因此不會加載關聯。
- 無需JVM來計算任何內容,JDBC結果就是計數。
TLDR:
的投影將使用少得多的CPU,存儲器,磁盤和/ O都在數據庫服務器和應用服務器水平和將不被網絡延遲作爲影響鑑於結果我是一個單一的值,不像更大的結果集可能。
雖然我知道人們喜歡不過早優化,我認爲,當我們需要從資源的東西,我們其實問這個資源給我們,我們要精確的,而不是試圖獲取所需的是非常重要的間接導致。這幾乎總是技術債務,你必須稍後再回來修復。
嘗試不用擔心性能問題,直到您實際注意到代碼運行緩慢。大多數情況下,像這樣的小事情無關緊要,你需要解決的事情將會在你不曾預料的地方。 – nhouser9
大部分同意@ nhouser9,但如果可行的話,這是一個應該使用內置計數方法的領域。這是一個非常易讀的優化,它摺疊了服務器端的數據。 – chrylis