使用Resque大量更新Rails中的许多记录?

时间:2013-01-30 23:56:38

标签: ruby-on-rails resque rails-activerecord

如果我必须更新50,000个用户,我将如何以最适合后台处理库而非N + 1问题的方式进行更新?

我有用户,会员和积分。

会员资格与总分值有关。如果使用点值修改成员资格,我必须通过所有用户来更新其正确的成员资格。这是我需要排队的,所以服务器不会挂30分钟。

现在我有一个控制器动作

def update_memberberships
  User.find_each do |user|
    user.update_membership_level! # looks for a Membership defined by x points and assigns it to user. Then Saves the user.
  end
end

这是一项非常昂贵的操作。我如何优化处理和后台处理,以便从表格中接近即时发布帖子?

2 个答案:

答案 0 :(得分:2)

您正在寻找update_all。来自文档:

如果所有记录与所提供的条件相匹配,则更新所有记录,还可以提供限制和订单。

在SQL方面可能还需要一段时间,但你至少可以用一个语句来做。 Check out the documentation查看用法示例。

答案 1 :(得分:2)

你似乎在追求如何使用Resque或delayed_job完成这项工作。我将举例说明delayed_job。

要创建作业,请向app / models / user.rb添加方法:

def self.process_x_update
  User.where("z = 1").find_each(:batch_size => 5000) do |user|
    user.x = user.y + 3
    user.save
  end
end
handle_asynchronously :process_x_update

这将更新z = 1的所有User条记录,设置user.x = user.y + 3.这将以5,000个批量完成此操作,因此性能更加线性。

这将导致User.process_x_update非常快速地完成。要实际处理作业,您应该在后台运行rake jobs:work或使用./script/delayed_job start

启动守护程序集群

另一件事:你能将这个逻辑移到一个SQL语句中吗?这样你就可以有一个快速和原子的语句。您仍然希望在后台执行此操作,因为它可能需要一些时间来处理。你可以这样做:

def process_x_update
  User.where("z = 1").update_all("x = y + 3")
end
handle_asynchronously :process_x_update