Rails 3.0.11迁移中的内存泄漏

时间:2012-03-16 12:24:10

标签: ruby-on-rails-3

迁移包含以下内容:

Service.find_by_sql("select 
                       service_id, 
                       registrations.regulator_given_id, 
                       registrations.regulator_id
                     from
                       registrations
                     order by
                       service_id, updated_at desc").each do |s|
  this_service_id = s["service_id"]
  if this_service_id != last_service_id
    Service.find(this_service_id).update_attributes!(:regulator_id => s["regulator_id"],                    
                   :regulator_given_id => s["regulator_given_id"])
    last_service_id = this_service_id
  end
end

并且正在耗尽内存,使其无法在Heroku允许的512MB中运行(注册表中有60,000项)。有一个已知的问题吗?解决方法?修复了Rails的更高版本?

提前致谢

编辑以下请求以澄清:
这是所有相关的来源 - 迁移的其余部分创建了两个正在填充的新列。情况是我在注册表中有来自多个来源(服务的监管机构)的服务数据。我决定将一些数据([prime] regulator_id和[prime] regulator_given_key)“推广”到主要监管机构的服务表中,以加速某些查询。

2 个答案:

答案 0 :(得分:0)

这将一次性加载所有60000个项目并保留这些60000 AR对象,这将消耗相当多的内存。 Rails确实提供了find_each方法,一次将这样的查询分解为1000个对象的块,但是它不允许你像指定那样排序。

您可能最好实现自己的分页方案。使用限制/偏移是可能的,但是大的OFFSET值通常是低效的,因为数据库服务器必须生成一堆然后丢弃的结果。

另一种方法是为查询添加条件,以确保不返回已处理的项,例如指定service_id小于先前返回的值。如果在这个问题上比较某些项目是相同的话,这就更复杂了。使用这两种分页类型方案,您可能需要考虑如果在处理它时将一行插入到您的注册表中会发生什么(可能不是迁移问题,假设您在禁用访问该站点的情况下运行它们)

答案 1 :(得分:0)

(注意:OP报告这不起作用)

尝试这样的事情:

previous = nil
Registration.select('service_id, regulator_id, regulator_given_id')
    .order('service_id, updated_at DESC')
    .each do |r|
  if previous != r.service_id
    service = Service.find r.service_id
    service.update_attributes(:regulator_id => r.regulator_id, :regulator_given_id => r.regulator_given_id)
    previous = r.service_id
  end
end

这是从regulators获取最新记录的一种hacky方式 - 毫无疑问,在SQL中使用DISTINCTGROUP BY进行更好的方式查询,这不仅会更快,而且更优雅。但这只是一次迁移,对吗?而且我没有保证优雅。我也不确定它是否会起作用并解决问题,但我认为所以: - )

关键的变化是,使用AREL,而不是使用SQL,这意味着(我认为)在每个关联的记录上执行一次更新操作,因为AREL返回它们。使用SQL,您可以将它们全部返回并存储在数组中,然后将它们全部更新。我也认为没有必要使用.select(...)子句。

对结果非常感兴趣,请告诉我它是否有效!