update_all with a method

让我们说我有一个模型:

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

而不是做

 Result.all.find_each do |s| s.sum = compute_sum(sx, sy) 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每条记录find_each创建自己的BEGINCOMMIT查询,并且每条记录都会单独更新。

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

如果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周围放置方括号。

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 – 我已经更新了我的答案。

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

 def self.sum x+y end