我在“heroku 运行控制台”上运行以下代码超过 15k 用户,它超过 512MB,如何优化此代码以停止内存不足?
User.all.each do |user|
user.authorization = 'enabled'
user.save!
end
为了简单起见,修改了这段代码,我在查询其他对象 VS user.authorization = 'enabled' 方面做了一些事情......我更想知道如何阻止内存泄漏?
我在“heroku 运行控制台”上运行以下代码超过 15k 用户,它超过 512MB,如何优化此代码以停止内存不足?
User.all.each do |user|
user.authorization = 'enabled'
user.save!
end
为了简单起见,修改了这段代码,我在查询其他对象 VS user.authorization = 'enabled' 方面做了一些事情......我更想知道如何阻止内存泄漏?
User.all
返回一个延迟加载的 activerecord 关系*,调用#each
该关系会导致该关系被加载到实例化对象的集合中,这与数据库中的用户数量成比例地消耗内存。
相反,这样做
User.find_each do |user|
user.authorization = 'enabled'
user.save!
end
#find_each
是一种 activerecord 方法,一次只实例化一个用户对象。此外,它将查询批处理成 1000 个用户的集合,从而减少给定时间的内存消耗。
* 在 Rails 4 中。在早期的 Rails 中,.all
将结果加载到实例化对象的集合中。
编辑:
顺便说一句,这个单线将具有相同的效果,但在单个查询中并且无需加载任何数据或实例化任何对象(这是最节省内存和时间的解决方案):
User.update_all(authorization: 'enabled')
根据文档:
循环访问数据库中的记录集合(例如,使用 all 方法)效率非常低,因为它会尝试一次实例化所有对象。
在这种情况下,批处理方法允许您批量处理记录,从而大大减少内存消耗。
使用ActiveRecord::Batches#find_each而不是仅使用 #each 遍历对象数组通常可以解决此问题;如果没有,请减少您的内存,:batch_size
直到它适合您的可用 RAM。