使用大型创建循环避免heroku R14错误

时间:2013-07-22 21:41:03

标签: ruby-on-rails ruby heroku

我有一个异步Resque作业,它在循环中创建了许多相关对象,我似乎无法避免heroku的R14错误。

  has_many :associated_things

  ...

  def populate_things
    reference_things = ReferenceThings.where(some_criteria).map(&:name) # usually between 10 k and 20k strings
    reference_things.each do |rt|
      self.associated_things << AssociatedThing.create name: rt
    end
  end

我尝试过的一些事情:

  • 将创建循环包装在ActiveRecord::Base.uncached
  • 在循环结束时手动运行GC.start
  • each_slice
  • 之前添加.each

有没有办法重写此循环以最小化内存使用?

2 个答案:

答案 0 :(得分:1)

@Plex Peachey有一些很好的建议,但最终@mu在第一条评论中有正确的想法。

过渡到原始SQL是我能找到的唯一方法。一些建议的方法在这里:

http://coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/

我使用了大量插入方法,它工作正常。

应该说,为什么这是必要的,我很清楚。显然,实例化数十万个AR对象 - 即使在Web请求之外,也是异步的 - 会导致内存泄漏。也许这只不是Rails / AR的设计目的。

相关问题,也许是同一个问题:ActiveRecord bulk data, memory grows forever

答案 1 :(得分:0)

可能有所帮助的一些想法:

由于您只是从nam提取ReferenceThings e,所以不要抓住完整的对象,然后抓住nam e。而是做这样的事情:

reference_things = ReferenceThings.where(some_criteria).pluck(:name)

这样可以更好地查询名称,并为您提供数组。明智的便宜得多。

我注意到你正在将所有正在创建的AssociatedThing放入数组中。如果你真的不需要它们的数组,那么只是创建它们会更好。如果你确实需要它们,根据你需要它们,你可以创建所有它们,然后查询数据库再次抓取它们并用find_each循环遍历它们,这将分批抓取它们。