update_all使用方法

时间:2015-10-20 08:25:26

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

假设我有一个模特:

class Result < ActiveRecord::Base
  attr_accessible :x, :y, :sum
end

而不是做

Result.all.find_each do |s|
  s.sum = compute_sum(s.x, s.y)
  s.save
end

假设compute_sum是一个可用的方法,并进行一些无法转换为SQL的计算。

def compute_sum(x,y)
  sum_table[x][y]
end

有没有办法使用update_all,可能是这样的:

Result.all.update_all(sum: compute_sum(:x, :y))

我要更新超过80,000条记录。 find_each中的每条记录都会创建自己的BEGINCOMMIT个查询,并且每个记录都会单独更新。

或者还有其他更快的方法吗?

3 个答案:

答案 0 :(得分:3)

update_all进行sql查询,因此对值进行的任何处理都需要在sql中。因此,您需要在您使用的任何DBMS中找到sql函数,以将两个数字相加。例如,在Postgres中,我相信你会这样做

Sum.update_all(sum: "x + y")

将生成此sql:

update sums set sum = x + y;

将计算每行的x + y值,并将sum字段设置为结果。

编辑 - 对于MariaDB。我从来没有使用过这个,但是一个快速的谷歌建议sql将是

update sums set sum = sum(x + y);

首先在sql控制台中尝试使用单个记录。如果它有效,那么你可以做

Sum.update_all(sum: "sum(x + y)")
在Rails中

EDIT2:这里有很多名为sum的东西,这使得这个例子非常混乱。这是一个更通用的例子。

将col_c设置为在类Foo中添加col_a和col_b的结果:

 Foo.update_all(col_c: "sum(col_a + col_b)")

我刚注意到我已经从您的问题中复制了(错误的)Sum.all.update_all。它应该是Sum.update_all - 我已经更新了我的答案。

答案 1 :(得分:3)

如果compute_sum函数无法转换为sql,则不能一次对所有记录执行update_all。您需要遍历各个实例。但是,如果列中有很多重复的值集,只需对每组输入进行一次计算,然后每次计算进行一次质量更新,就可以加快速度。例如

Result.all.group_by{|result| [result.x, result.y]}.each do |inputs, results|
  sum = compute_sum(*inputs)
  Result.update_all('sum = #{sum}', "id in (#{results.map(&:id).join(',')})")
end

您可以将result.x,result.y替换为compute_sum函数的实际输入。

编辑 - 忘记在group_by块中的result.x,result.y周围放置方括号。

答案 2 :(得分:1)

我完全是初学者,只是想知道为什么不添加如下所示的自我阻止,而不在db中添加单独的列,你仍然可以从外部访问Sum.sum。

def self.sum 
x+y 
end