我的Ruby on Rails应用程序拥有100,000,000个用户。我在模型上有一个名为'data'的列,它是一个JSON字段,它包含一个相当小的JSON对象,我希望通过保存到一个新字段进行备份。
如果我有1,000个用户,我可以直接运行:
users = User.all
users.each do |user|
user.data_backup = user.data
user.save
end
并将现有数据保存到新列。但是,对于这么多用户来说,这可能会永远占用。当我拥有100,000,000多名用户时,大规模更新模型上任何字段的正确和/或最有效方法是什么?
答案 0 :(得分:2)
对于大量记录,请尝试使用find_in_batchs方法
User.find_in_batches(batch_size: 1000) do |users|
users.each do |user|
user.data_backup = user.data
user.save
end
end
答案 1 :(得分:0)
可以在SQL中完成:
sql = "UPDATE users SET data_backup = data"
ActiveRecord::Base.connection.execute(sql)
或update_all
:
User.update_all('data_backup = data')
答案 2 :(得分:0)
我们有一个场景,我们必须迭代一大堆记录并调用相应的通知。
User.all.each do |user|
NewsMailer.weekly(user).deliver_now
end
上述代码可以满足我们的最终目标。 但是随着表大小的增加,这种方法变得越来越不切实际,因为User.all.each指示Active Record在一次传递中获取整个表,每行构建一个模型对象,然后将整个模型对象数组保留在内存中。实际上,如果我们有大量记录,整个集合可能会超过可用内存量。
必须执行批量更新的方案,Rails提供了通过将记录划分为内存友好批处理来解决此问题的方法。
find_each,检索一批记录,然后将每个记录单独作为模型生成到块中。
User.find_each(batch_size: 5000) do |user|
NewsMailer.weekly(user).deliver_now
end
或
另一个例子是,如果您希望多个工作人员处理相同的处理队列。通过在每个worker上设置相应的:start和:finish选项,您可以让每个worker处理10000条记录。
User.find_each(start: 2000, finish: 10000) do |user|
NewsMailer.weekly(user).deliver_now
end
find_in_batches,检索一批记录,然后将整批产品作为模型数组生成块。 find_in_batches方法类似于find_each,因为它们都检索批量记录。区别在于find_in_batches将块作为模型数组生成,而不是单独生成。
User.find_in_batches do | user |
NewsMailer.weekly(user).deliver_now
端