2012-05-31 68 views
4

我有一個java jpa/hibernate應用程序,需要獲取大量數據才能執行其任務。我遇到了n + 1問題,所以我決定使用hibernate.default_batch_fetch_size(@batchsize)屬性來降低所需的sql往返次數。我嘗試了一些價值觀,但表現幾乎與所有嘗試過的價值觀相撞。使用@batchsize後jpa性能崩潰

BATCHSIZE:0 - sql語句發送:14000 - 持續時間:約1分鐘

BATCHSIZE:4 - sql語句發送:5000 - 持續時間:大於10分鐘

BATCHSIZE:10 - sql語句發送:2700 - 持續時間:約5分鐘

BATCHSIZE:100 - sql語句發送:400 - 持續時間:約1分鐘

這是一個 「正常」 的行爲?如果不是什麼可以是錯誤的?

我用log4jdbc記錄了生成的sql。我注意到,在每一個批處理的聲明之間撒謊約100-150毫秒。如果我以後運行SQL,每個語句的運行時間不超過20毫秒。所以這不會成爲DB(IN語句)相關問題。

的Java:1.6.0_31,Hibernate的3.6.7,DB的Postgres 9.1.1,JDBC PostgreSQL相關9.1-901.jdbc4.jar

在此先感謝

更新 把事情清楚的:性能損失是在批量獲取期間沒有批量更新/插入

回答

5

經過一些調試後,我發現這個問題。 Hibernate(至少在版本3.6.7中)將映射的所有映射集合存儲在映射中。你可以用這樣的snipplet訪問這些地圖:

SessionImpl si = ((SessionImpl) entityManager.getDelegate()); 
PersistenceContext persistenceContext = si.getPersistenceContext(); 
persistenceContext.getCollectionEntries(); 

所以每次採集創造了這個map.If你有很多藏品的POJO喜歡在我的情況下,這個變大快一個條目。例如,每個32個集合加載的10.000個pojos都有320.000個收集條目。 Hibernate現在只是迭代地圖(org.hibernate.engine.BatchFetchQueue.getCollectionBatch(CollectionPersister,Serializable,int,EntityMode))來查找未加載的Collection ID,以便稍後將它們放入IN子句中。 Hibernate不會將搜索關鍵限制在某種類型的集合中,所以這會變得更糟。

我想我必須清理一些集合,並希望hibernate獲得更高效的方式來找到更高版本中的鍵。

更新: https://hibernate.onjira.com/browse/HHH-1775?focusedCommentId=42686&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-42686

更新: 這樣問題就不客氣休眠版本:4.1.8

此有關休眠JIRA評論也許有人同樣的問題很有趣