2011-08-03 5 views
4

それぞれが多数の関連項目を持つ多数のレコード(Merchants)を反復処理する必要があるレーキタスクがあります。私の問題は、Railsが自動的にDBクエリの結果をキャッシュするため、私は非常に長い間、スワップスペースに従業員を入れることになります。 「アイテム」を介して各時間の値をキャッシュせずに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; print "#{m.id}"}、各繰り返しでメモリ使用量にバンプがあります。これは、m.itemsが1〜10,000 + ActiveRecordsの間にあるためです。 – peter

答えて

3

あなたの会合はこれを試すことができ、簡単なhas_many 1の場合:

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'配列を解放するまで(つまり 'each'ループを終了するまで)リリースされませんが、私の場合は' items'が解放され、再割り当て後にガベージコレクションされます次の 'each'繰り返し。 –

+0

はいはいはい。あなたは私の心を吹き飛ばした。ありがとうございました。 – peter

4

クエリキャッシュはここでの主な問題ではありませんが。とにかくあなたのオブジェクトを "キャッシュ"します。

クエリキャッシュは、単にRailsがDBに不必要に当たるのを防ぐ「ハッシュルックアップ」であり、ルビ(またはRails)が内部的に関連付けによって返されたオブジェクトをどのように格納するかを制御しません。例えば

この(でも、キャッシュされていない場合)を試してください:あなたはeachループでm.itemsを行う際だから今あなたは、単にすべての項目をすべてMerhcantのインスタンスを移入し、ガベージコレクタがすることができません

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 

をあなたがループ内にいる間にすべてのオブジェクトがall配列から参照されているので、何も無料にしてください。

解決策は、Victor提案のようにすることです。これにより、「関連ストレージ」がトリガーされなくなります。

+0

お寄せいただきありがとうございます。わかった :) – peter

関連する問題