2009-11-23 141 views
9

我最近有一個相當奇怪的現象。必須獲得一個計數,其中包括使用不同WHERE條件連接多個表的計數。我首先使用hibernate的標準API實現了查詢。它正確地創建了請求的準備好的SQL語句,但速度很慢。然後使用HQL重新實現整個查詢。相當討厭這樣做,但結果表現比Criteria API要快得多。有人知道這種行爲的原因嗎?我認爲Criteria和HQL框架使用相同的代碼庫將其轉換爲SQL。休眠查詢與條件績效

下面是該查詢:

select count(*) from R r where r.ISREPLACEDBY = 0 
and r.STATUS='OK' and r.A = ? 
and r.C in 
    (select distinct RC from CX cx where cx.FROMDATE >= ? and cx.FROMDATE <=?) 
+0

一些額外的信息您可以顯示HQL和條件查詢? – 2009-11-23 18:46:58

+0

查詢取決於參數。其中一個較簡單的陳述如下所示: 從R r中選擇count(*),其中r.ISREPLACEDBY = 0且r.STATUS ='OK'且r.A =?和r.C in(從CX cx中選擇不同的RC,其中cx.FROMDATE> =?和cx.FROMDATE <=?) – bertolami 2009-11-24 12:37:10

回答

17

我猜我終於找到原因了。似乎標準API會在每次執行準備好的語句時創建新的變量名稱。數據庫(在我們的例子中是DB2)每次執行語句時計算一個新的查詢執行計劃。另一方面,HQL使用相同的變量名稱,允許數據庫重新使用查詢執行計劃。

0

我一般認爲,HQL是非常接近最優的,因爲它幾乎是直接的SQL與一些換人。我假設從HQL到SQL的轉換隻是替代; Criteria API可能會生成HQL然後進行轉換。一般來說,HQL是你最好的選擇。

+2

實際上,Criteria直接轉換爲SQL。例如Criterion.toSqlString – qualidafial 2011-07-20 16:23:28

+0

實際上並非如此。它首先生成HQL,然後解析。 – mnp 2013-11-26 08:34:16

0

Hibernate的標準使用反射來生成SQL Statments

+0

標準API的另一個問題是它每次都會生成HQL(當然,因爲每次都可能會有所不同)。這個HQL每次都會被轉換成SQL。該翻譯嘗試通過拋出ClassNotFoundException的類加載器(例如generatedBla0)加載一些令牌。這是非常昂貴的操作,因爲它在所有類加載器通過所有類加載器之前最後一個可以拋出異常,並且在類加載器中涉及一些會嚴重影響性能的鎖。忘了提及由於一個bug,可能會將整數插入到SQL中而不是params中。 – mnp 2013-11-26 08:36:35

3

標準,理論上應該比一個HQL查詢的開銷以下(不含命名查詢,我會得到)。這是因爲Criteria不需要解析任何東西。 使用基於ANTLR的解析器分析HQL查詢,然後將生成的AST轉換爲SQL。 但是,使用HQL/JPAQL,您可以定義命名查詢,在SessionFactory啓動時生成SQL。理論上,命名查詢的開銷比Criteria少。 所以,在SQL代開銷方面,我們有:

  1. 命名的HQL/JPAQL查詢 - SQL生成只發生一次。
  2. 準則 - 在生成之前無需解析。
  3. (非命名)HQL/JPAQL查詢 - 解析,然後生成。也就是說,選擇基於解析和SQL生成開銷的查詢技術在我看來可能是一個錯誤。 與使用真實數據在真實數據庫服務器上執行真實查詢相比,此開銷通常非常小。如果這種開銷實際上在分析應用程序時顯示出來,那麼也許你應該切換到一個命名查詢。

這裏有標準和HQL/JPAQL之間進行選擇時,我考慮的事情:

  • 首先,你必須決定,如果你真行具有在 Hibernate的專有API的依賴你碼。 JPA沒有標準。
  • 準則非常擅長處理許多可選搜索參數 ,例如您可能會在具有多參數 「搜索表單」的典型網頁上找到的參數。使用HQL,開發人員傾向於使用StringBuilder在表達式的條款 (避免這個!)。根據標準,你不需要這樣做。
  • HQL/JPAQL可以用於大多數其他事情,因爲代碼傾向於 越小越容易讓開發人員理解。
  • 如果您使用 HQL,則可以將真正頻繁的查詢轉換爲命名查詢。我更喜歡稍後再做一些分析。

你可以在這裏閱讀http://tech.puredanger.com/2009/07/10/hibernate-query-cache/