2

可以說我有一個模型:update_all與方法

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查詢,並且每個記錄都單獨更新。

還有沒有其他更快的方法來做到這一點?

+0

我有範圍和'where(...)'從句代替'all'。 –

+0

如果你的總和(s.x,s.y)方法是ruby,你別無選擇,只能做你在這裏做的事情。你真正想要的是讓數據庫執行一個代碼。你應該嘗試爲它寫一個sql腳本。一些想法:http://stackoverflow.com/questions/4278582/sql-field-as-sum-of-other-fields。 – muichkine

+0

您正在使用哪種DMBS?即postgres,MySQL等? –

回答

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函數的實際輸入。

編輯 - 忘記把result.x放在group_by塊的result.x中。

+0

謝謝!這會加速它..與@ lx00st建議混合在一起[ActiveRecord :: Base.transaction](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)包裝整個事情可以加快它...我正在測試這個。 –

3

update_all作出一個SQL查詢,所以你對這些值所做的任何處理都需要在sql中。所以,你需要在你使用的任何DBMS中找到sql函數,將兩個數字一起添加。在Postgres的,例如,我相信你會做

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

這將產生這樣的SQL:

update sums set sum = x + y; 

將計算X + Y值的每一行,其和字段設置爲結果。

編輯 - 爲MariaDB。我從來沒有使用過這一點,但快速谷歌表明,SQL是

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

試試這個第一,在你的SQL控制檯,單個記錄。如果有效,那麼你可以做

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

in Rails。

EDIT2:在這裏有很多東西叫sum這使得這個例子很讓人困惑。這是一個更通用的例子。

集col_c以增加爲col_a和col_b在一起,在類Foo的結果:

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

我只注意到我複製從你的問題了(不正確)Sum.all.update_all。它應該是Sum.update_all - 我已經更新了我的答案。

+0

非常感謝。 IRL求和函數是一個二維查找表(數組,未存儲在數據庫atm中)。本質上,如下所示: 'def sum(x,y) sum_table [x] [y] end' –

+0

我很困惑。數據庫中的「sum」表中是否有「sum」列?如果沒有,那麼試圖用'update_all'來設置它永遠不會起作用。 –

+0

是的,有一個'sum'列。我想說明的是,我想用'col_A'和'col_B'作爲輸入來計算'col_C' ...'sum'就是一個例子。 –

1

我完全是初學者,只是想知道爲什麼不添加一個像下面的自我塊,沒有在數據庫中添加單獨的列,您仍然可以從外部訪問Sum.sum。

def self.sum 
x+y 
end 
+0

上面的例子只是一個例子。我想說明的是我想用'col_A'和'col_B'作爲輸入來計算'col_C'。 是的,數據確實需要放在表格中。 –

+0

這是問題的答案,您可以通過多種方式獲得相同的結果。 –