2013-05-26 74 views
0

我有以下(過於昂貴分貝)方法:使用獨立值更新多個記錄的有效方法?

def reorder_area_routes_by_demographics! 
     self.area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).readonly(false).each_with_index do |area_route, i| 
     area_route.update_attributes(match_rank: i) 
     end 
    end 

但是這會導致對每個area_route的UPDATE查詢。有沒有辦法在一個查詢中做到這一點?

- 編輯 -

最終的解決方案,每coreyward建議:

def reorder_area_routes_by_demographics! 
    sorted_ids = area_routes.joins(:route).order(self.demo_criteria, :proximity_rank).pluck(:'area_routes.id') 
    AreaRoute.update_all [efficient_sort_sql(sorted_ids), *sorted_ids], {id: sorted_ids} 
end 

def efficient_sort_sql(sorted_ids, offset=0) 
    offset.upto(offset + sorted_ids.count - 1).inject('match_rank = CASE id ') do |sql, i| 
    sql << "WHEN ? THEN #{id} " 
    end << 'END' 
end 
+0

如果您更新表的新數據位於數據庫中,則可以在db上運行查詢以在一個事務中更新'area_route'中的所有值。這將比逐行更新行更快。我不熟悉Ruby,所以如果你可以將語句翻譯成SQL或者告訴邏輯,那麼我可以給你寫這個SQL。 – Stoleg

回答

1

我用下面做一個類似的任務:更新記錄一羣的排序位置,根據他們的訂單在params。您可能需要重構或合併,以適應您所應用的範圍,但我認爲這會使您朝正確的方向發展。

def efficient_sort_sql(sortable_ids, offset = 1) 
    offset.upto(offset + sortable_ids.count - 1).reduce('position = CASE id ') do |sql, i| 
    sql << "WHEN ? THEN #{i} " 
    end << 'END' 
end 

Model.update_all [efficient_sort_sql(sortable_ids, offset), *sortable_ids], { id: sortable_ids } 

sortable_ids是表示每個對象的ID的整數數組。生成的SQL看起來是這樣的:

UPDATE pancakes SET position = CASE id WHEN 5 THEN 1 WHEN 3 THEN 2 WHEN 4 THEN 3 WHEN 1 THEN 4 WHEN 2 THEN 5 WHERE id IN (5,3,4,1,2); 

這是,醜陋之外,一個漂亮的高性能查詢和(至少在PostgreSQL)要麼完全成功,要麼完全失敗。

+0

真棒!這工作完美。上面添加的最終解 – John

相關問題