如何按比例更新User对象?

时间:2017-08-18 00:33:22

标签: ruby-on-rails ruby bigdata

我的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多名用户时,大规模更新模型上任何字段的正确和/或最有效方法是什么?

3 个答案:

答案 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提供了通过将记录划分为内存友好批处理来解决此问题的方法。

  1. find_each,检索一批记录,然后将每个记录单独作为模型生成到块中。

     User.find_each(batch_size: 5000) do |user|
          NewsMailer.weekly(user).deliver_now
     end
    

  2. 另一个例子是,如果您希望多个工作人员处理相同的处理队列。通过在每个worker上设置相应的:start和:finish选项,您可以让每个worker处理10000条记录。

    User.find_each(start: 2000, finish: 10000) do |user|
      NewsMailer.weekly(user).deliver_now
    end
    
    1. find_in_batches,检索一批记录,然后将整批产品作为模型数组生成块。 find_in_batches方法类似于find_each,因为它们都检索批量记录。区别在于find_in_batches将块作为模型数组生成,而不是单独生成。

      User.find_in_batches do | user |

        NewsMailer.weekly(user).deliver_now