我有一个rake任务需要遍历大量记录(称为Merchants),每个记录都有大量关联项。我的问题是,由于Rails会自动缓存我的数据库查询的结果,我最终会将我的工作人员放入交换空间。
简而言之,我想知道如何运行如下命令:
Merchant.all.each { |m| items = m.items }
每次都没有缓存'items'的值。
我试过了:
Merchant.all.each do |m|
ActiveRecord::Base.connection.uncached do
items = m.items
end
end
我也尝试将其添加到我的Merchant模型中:
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
尝试进行一些错误检查,然后记录结果。
答案 0 :(得分:4)
查询缓存不是此处的主要问题。无论如何,Rails“缓存”你的对象。
查询缓存只是一个“哈希查找”,可以防止Rails不必要地访问数据库,它不会控制ruby(或Rails)如何存储关联内部返回的对象。
例如试试这个(即使是未缓存的):
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
所以现在当你在m.items
循环中执行each
时,只需用所有项目填充所有Merhcant
个实例,并且垃圾收集器无法释放任何内容,因为所有对象在循环内部时从all
数组引用。
所以解决方案就像Victor提出的那样,它可以阻止“关联存储”的触发。
答案 1 :(得分: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