2012-08-10 172 views
0

我正在處理一些性能問題,這些問題看起來與重複調用數據庫(幾千個對象,每個都有幾十個子對象)有關。Grails/hibernate Eager提交似乎被忽略

問題似乎是,儘管加載關係(並確認對象實際上是通過記錄hibernate SQL實際加載的),但它們仍然每次都從數據庫中獲取。

我的直覺是問我是否有辦法告訴grails/hibernate在內存中使用這個對象,而不是回到數據庫,因爲我肯定它已經在內存中了?

雖然這可能是錯誤的問題。


給出一個具體的例子。我的域類父定義:

static hasMany = [children: Child] 
static mapping = {children fetch:'select'} 

可能已經獲取:「渴望」 ......我想兩者兼得,不知道哪個產生下面的日誌結果,但它顯然急切地獲取數據。

我做的第一件事是:

高清結果= Parent.executeQuery(「從父p選擇不同的P其中......複雜的where子句」)

查看日誌,這不急切地加載孩子的關係,但這並不是非常意外,並且在這一點上並不是真正的殺手。接下來,我遍歷整個家長:

for(Parent parent : results) 
{ blah blah } 

循環的每次迭代顯示,Hibernate是根據ID查詢父p和似乎急切地加載所有子關係。日誌片段:

select 
parent0_.id as id4_4_, 
parent0_.version as version4_4_, 
parent0_.date_created as date3_4_4_, 
child1_.parent_id as parent6_6_, 
child1_.id as id6_, 
child1_.child_idx as idx9_6_, 
child1_.id as id22_1_, 
child1_.version as version22_1_, 
...continues for all fields. 

注意:我不知道爲什麼它將id字段映射兩次。

太棒了!它急切地加載我需要的子對象!在上面的父循環中,我然後迭代孩子:

for(Parent parent : results) 
{ 
    for(Child child : parent.children) 
    { blah blah } 
} 

而這就是問題所在。在內部循環的每次迭代中,都會記錄另一個hibernate查詢,通過id加載對象。日誌片段:

select child0_.id as id22_1_, 
child0_.version as version22_1_, 
child0_.parent_id as parent6_22_1_, 
child0_.sequence_number as sequence8_22_1_, 
...and all the rest 

這些不必要的負荷是絕對殺死我的表現(至少,這似乎是瓶頸,我不能100%確定),因爲它的執行數千讀取。非常感謝您對如何正確使用內存對象或不同方式加載數據的任何想法。

回答

0

我發現在mapping中設置fetch不足以讓grails使用預先抓取。雖然它在gorm手冊中沒有提到,但還有另外一個屬性fetchMode似乎是必要的。嘗試添加給你的域類:

static fetchMode = [children: 'eager'] 
+0

感謝您的建議,任何事情都值得一試,當你卡住了。 – Trebla 2012-08-15 12:31:08

0

這應該是毫不奇怪誰意識到,我必須做一些錯誤的...我做錯了什麼人。該對象正在被緩存,但是在子例程中調用了parent.refresh()。看起來刷新正在執行多個查詢來加載子對象,一旦刷新被刪除,我不再看到額外的查詢,但似乎刷新應該執行與初始加載相同的單一查詢而不是查詢孩子的對象。我的代碼中可能還有其他錯誤,我沒有完全調試。