阻止Rails缓存ActiveRecord查询的结果

时间:2011-08-03 23:12:27

标签: mysql ruby-on-rails ruby caching activerecord

我有一个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

尝试进行一些错误检查,然后记录结果。

2 个答案:

答案 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