我有以下(过度数据库昂贵)方法:
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 :(得分: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中)将完全成功或完全失败。