0

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

有没有办法重写这个循环来最小化内存使用?

4

2 回答 2

1

@Alex 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

于 2013-07-31T17:26:42.687 回答
0

一些可能有帮助的想法:

由于您只是nam从 中拉出 e ReferenceThings,因此不要抓住整个对象,然后再抓住name。而是做这样的事情:

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

这将做一个更好的查询,只抓取名称并给你一个数组。更便宜的内存明智。

我注意到您正在将AssociatedThing您正在创建的所有 s 放入一个数组中。如果您实际上并不需要它们的数组,那么仅创建它们会更好。如果您确实需要它们,则根据您需要它们的内容,您可以全部创建它们,然后查询数据库以再次获取它们并循环遍历它们,find_each这将分批获取它们。

于 2013-07-23T02:31:41.720 回答