2011-08-03 58 views
4

我有一個rake任務,需要遍歷大量記錄(稱爲商家),每個記錄都有大量的關聯項目。我的問題是,由於Rails自動緩存我的數據庫查詢的結果,我最終將我的工作人員放入交換空間很長時間。防止導致ActiveRecord查詢結果緩存導致

總之,我想知道如何運行像這樣的命令:沒有緩存,每次通過「項目」的值

Merchant.all.each { |m| items = m.items }

我已經試過:

Merchant.all.each do |m|` 
    ActiveRecord::Base.connection.uncached do 
    items = m.items 
end 
end 

和我也嘗試添加這對我的商家模式:

def items_uncached 
    self.class.uncached { items } 
end 

,然後調用items_uncached代替,但我最終仍費盡了內存使用情況以及我訪問的每一組新項目。

我正在運行Rails 2.3.10,Ruby 1.9.2並使用Mysql進行存儲。

在此先感謝您的想法!

*編輯:

這裏是我工作的實際代碼位:

File.open(output, "w") do |f| 
    Merchant.all.each do |m| 
    items = m.items 
    invalid_image_count = 0 
    items.each do |i| 
     invalid_image_count += 1 unless i.image_valid? 
    end 
    invalid_categories = items.select { |i| !i.categories_valid? }.count 
    f.puts "#{m.name} (#{m.id}): #{invalid_image_count} invalid images, " + 
      "#{invalid_categories} invalid categories" 
    end 
end 

試圖做一些錯誤檢查,然後記錄結果。

+1

你想要做的事情在這裏不是很清楚;也許你正在尋找像'ActiveRecord :: Base#find_each'? – coreyward

+0

好的,是的,我只是看着find_each,實際上可能會有所幫助。我會試試看。 – peter

+0

爲了表達更好一點,當我在控制檯中運行此代碼時:Merchant.all.each {| m | items = m.items;打印「#{m.id}」},在每次迭代中,我的內存使用情況都會出現波動。我的猜測是,這是由於m.items產生1至10,000以上的ActiveRecords。 – peter

回答

3

如果你的公會是一個簡單的has_many一個你可以試試這個:

Merchant.all.each do |m| 
    items = Item.find_all_by_merchant_id(m.id) 
    ... 
end 

甚至:

Merchant.find(:all, :select => "id, name").each do |m| 
    items = Item.find_all_by_merchant_id(m.id) 
    ... 
end 
+0

我不確定這是否會避免緩存。這是一個簡單的has_many關係,但我認爲在這種情況下,m.items應該與Item.find_all_by_merchant_id(m.id)具有相同的效果/返回值。這聽起來正確嗎? – peter

+0

我相信'm.items'在您釋放'Merchant.all'數組之前不會被釋放(即,直到您完成每個''循環),而在我的情況下,'items'將被釋放並且在您重新分配之後收集垃圾下一個「每個」迭代。 –

+0

是的是的。你只是吹了我的腦海。謝謝。 – peter

4

查詢緩存不是主要問題就在這裏。無論如何,Rails「緩存」你的對象。

查詢緩存只是一個「哈希查找」,它可以防止Rails不必要地點擊數據庫,它不控制ruby(或Rails)如何存儲由關聯在內部返回的對象。在each循環,這樣,當你做m.items現在

m = Merhant.first # <- m is loaded from DB 
m.items   # <- items are loaded from DB and STORED(!) in m 
m.items   # <- items are returned from the association stored in m 
m.items.reload # <- hits the DB (or the query cache) 
m.instance_variable_get("@items") # <- returns the actual stored items 

您只需填充所有Merhcant情況下,與他們的所有項目,以及垃圾收集器不能:

例如試試這個(即使未緩存)釋放任何東西,因爲所有對象都在循環內時從all數組引用。

因此,解決方案就像Victor提出的那樣,它可以防止「關聯存儲」觸發。

+0

非常感謝您的進一步闡述。我現在得到它:) – peter