2012-10-18 180 views
0

在某些情況下,當我得到一個ActiveRecord的關係,我在一個ActiveRecord遇到奇怪的行爲與.each ::關係Rails的活動記錄關係枚舉

這似乎是在ActiveRecord的::關係代表:each:to => :to_asource

@tasks = Task.find_task(list, {:week_id => 1}) 

基本上,有一個長的類方法,它採用一個對象(list,並用:week_id散列)

過濾一束&查詢發生這種find_task方法中,但它最終返回一個關係到@tasks

然後,在模板中,我有:

<% @tasks.each do |task| %> 
. 
. 
. 
<% end %> 

無論出於何種原因,無論是大小爲@tasks,大約需要3分鐘。我可以通過調用@tasks.to_a來複制相同的行爲即使@tasks,ActiveRecord :: Relation的實例只有兩條記錄,在它們上調用to_a需要> 3分鐘。

它不會發生在所有:week_id S,只能在特定的week_id,例如::week_id => 1

的SQL執行罰款,我得到一個關係回來,它只是似乎是一個枚舉上一個問題特定的ActiveRecord ::關係。

更新

算法(我認爲這意味着類方法),我做的預先加載的裏面很多。所以Postgres做了很多LEFT OUTER JOIN s,我已經索引了所有需要發生的表。

一個解釋分析顯示,所有掃描都是index scans,事實證明,查詢執行得很好,有很多急切的加載......並且我得到一個渴望加載的'ActiveRecord :: Relation'回到合理的數量時間。

更新2 雖然這個過程是服用3分鐘,我看到了幾秒鐘一個Postgres處理運行,然後我看到這3分鐘我的輸出top

PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND                
8685 dylan  20 0 3407m 2.6g 904 R 99.7 69.1 1:14.49 /usr/local/bin/ruby script/rails s 

當它終於結束時,服務器顯示這個;

  • 預先加載:200 ms139 ms然後
  • 大的SQL查詢,有很多LEFT OUTER JOINS in 33,000 ms,(長,但不是其中大部分是),那麼
  • 模板257,000 ms

當我複製模板的行爲我看到它大約需要3-4分鐘撥打to_a@tasks關係。

所以,當我的服務器告訴我所有的時間都花在模板上,而且我可以看到調用一個關於enumerable的關係需要永遠的時間,是當查詢被執行時?儘管在top我只能看到ruby進程正在運行?

回答

0

原來的問題是急於加載。當在ActiveRecord :: Relation實例上調用可枚舉方法時,它將被委託給.to_a,而在Ruby中,.to_a方法可能需要很長時間才能處理大量關係。儘管我通過@tasks循環播放,但我仍然渴望加載如此多的對象,以至於.to_a花費的時間過長。

我的短期解決方案是簡單地熱切加載較少的對象。它最終以n + 1查詢傷害了我,但我的.to_a方法不再瘋狂。

這是我能想到的唯一解釋。

0

我知道這是一箇舊的帖子,但爲了將來的參考,這將通過使用find_each來解決。

你可以在Ruby on Rails guides找到更多的信息。