2013-01-12 121 views
11

我在Oracle上檢測到hibernate和本機查詢的性能問題。當我用TOAD上的幾個參數執行一個複雜的SQL查詢時,我以毫秒爲單位得到結果。但是,當我使用Hibernate執行相同的查詢時,這個時間會大大增加(最多4秒或甚至更多)。在Hibernate + Java上性能下降,但在使用相同的本機Oracle查詢使用TOAD時速度很快

我的SQL查詢相當複雜,返回一個唯一值(因此,問題與安裝類所需的時間無關),它包含幾個格式爲':nameParameter'的參數。該查詢存儲在一個字符串中。例如,

String myNamedNativeQuery = "select count(*) from tables "+ 
          "where column1 = :nameParameter1 "+ 
          "and column2 = :nameParameter2"; 
          //actually my sentence is much more complex!! 

當我在TOAD上執行該句子時,它會在幾個毫秒內解析出來。但是用這句話與Hibernate

SQLQuery query = session.createSQLQuery("myNamedNativeQuery"); 

query.setParameter(nameParameter1, value1); 
query.setParameter(nameParameter2, value2); 

query.uniqueResult(); 

需要幾秒鐘才能得到同樣的結果。

我意識到如果我直接在本機查詢中替換參數,然後使用Hibernate執行這個句子,時間會大大減少。這將是這樣的:

String strQuery = session.getNamedQuery("myNamedNativeQuery").getQueryString(); 

myNamedNativeQuery = myNamedNativeQuery.replace("nameParameter1", value1); 
myNamedNativeQuery = myNamedNativeQuery.replace("nameParameter2", value2); 

SQLQuery query = session.createSQLQuery("myNamedNativeQuery"); 
query.uniqueResult(); 

任何人都知道發生了什麼?

在此先感謝。

PS:Oracle的版本是9i和休眠3.2

+1

用hibernate打開「show sql」選項。它會告訴你hibernate正在運行的查詢,並會告訴你爲什麼它需要這麼長時間。 –

回答

6

我認爲正在發生的事情與此代碼:

SQLQuery query = session.createSQLQuery("myNamedNativeQuery"); 
query.setParameter(nameParameter1, value1); 
query.setParameter(nameParameter2, value2); 
query.uniqueResult(); 

是這樣的:以創建一個查詢計劃:

第1行在您的命名參數的一些預期值。

第4行:查詢與value1和值2執行,但這些值是不是因爲這是第1行精心製作等,該數據庫正在執行一個實際的一個非常不恰當的計劃的查詢計劃「良好的價值觀」值,它需要很長的時間。

爲什麼?

綜觀HibernateSessionImpl.createSQLQuery(...)的源代碼,我發現這行代碼:

SQLQueryImpl query = new SQLQueryImpl(
       sql, 
         this, 
         factory.getQueryPlanCache().getSQLParameterMetadata(sql) 
     ); 

它調用getQueryPlanCache()一些parameterMetaData。我假設這個元數據不是夠好

+0

有趣......那麼,在這些情況下最好的做法是什麼?也許在調用createSQLQuery()之前用它們的值替換參數? – Sobrino

+0

也許自適應光標共享會有所幫助。但該功能在11g之前不可用。 –

+0

根據我的測試,這種情況也使用session.getNamedQuery('myNamedQuery')。看起來Hibernate正在緩存查詢計劃,並且選擇的查詢計劃的一些參數並不是最好的。那麼,是否可以配置查詢計劃緩存? – Sobrino

0

我的回答給您的是:

刪除所有綁定參數和使用StatelessSession代替會議

使用的SQLQuery,而不是查詢的全SQL,包括參數值

StatelessSession session = sessionFactory.openStatelessSession(); 

我有類似的問題直到我得到更好的解決方案,這是我設法使其工作。 請參閱Hibernate parameterized sql query slow and active oracle sessions

相關問題