Avi*_*hai 64 sql activerecord ruby-on-rails
我正在尝试使用ActiveRecord的find_each方法运行大约50,000条记录的查询,但它似乎忽略了我的其他参数,如下所示:
Thing.active.order("created_at DESC").limit(50000).find_each {|t| puts t.id }
Run Code Online (Sandbox Code Playgroud)
而不是停留在50,000我喜欢和排序created_at,这是在整个数据集上执行的结果查询:
Thing Load (198.8ms) SELECT "things".* FROM "things" WHERE "things"."active" = 't' AND ("things"."id" > 373343) ORDER BY "things"."id" ASC LIMIT 1000
Run Code Online (Sandbox Code Playgroud)
有没有办法获得类似的行为,find_each但总的最大限制和尊重我的排序标准?
Dir*_*urs 63
文档说find_each和find_in_batches不保留排序顺序和限制,因为:
您可以像@rorra一样编写自己的此函数版本.但是在改变对象时你会遇到麻烦.例如,如果按create_at排序并保存对象,则可能会在下一批次中再次出现.同样,您可能会跳过对象,因为在执行查询以获取下一批时,结果的顺序已更改.仅将该解决方案与只读对象一起使用.
现在我主要担心的是我不想一次将30000+个对象加载到内存中.我担心的不是查询本身的执行时间.因此,我使用了一个执行原始查询但只缓存ID的解决方案.然后它将ID数组分成块,并按块查询/创建对象.这样您就可以安全地改变对象,因为排序顺序保存在内存中.
这是一个类似于我所做的最小例子:
batch_size = 512
ids = Thing.order('created_at DESC').pluck(:id) # Replace .order(:created_at) with your own scope
ids.each_slice(batch_size) do |chunk|
Thing.find(chunk, :order => "field(id, #{chunk.join(',')})").each do |thing|
# Do things with thing
end
end
Run Code Online (Sandbox Code Playgroud)
该解决方案的权衡取舍是:
希望这可以帮助!
ror*_*rra 24
find_each在引擎盖下使用 find_in_batches.
如find_in_batches中所述,无法选择记录的顺序会自动设置为在主键("id ASC")上升序以使批量订购工作.
但是,应用标准,您可以做的是:
Thing.active.find_each(batch_size: 50000) { |t| puts t.id }
Run Code Online (Sandbox Code Playgroud)
关于限制,它尚未实现:https: //github.com/rails/rails/pull/5696
回答第二个问题,您可以自己创建逻辑:
total_records = 50000
batch = 1000
(0..(total_records - batch)).step(batch) do |i|
puts Thing.active.order("created_at DESC").offset(i).limit(batch).to_sql
end
Run Code Online (Sandbox Code Playgroud)
Tho*_*emm 16
检索第ids一个并处理in_groups_of
ordered_photo_ids = Photo.order(likes_count: :desc).pluck(:id)
ordered_photo_ids.in_groups_of(1000, false).each do |photo_ids|
photos = Photo.order(likes_count: :desc).where(id: photo_ids)
# ...
end
Run Code Online (Sandbox Code Playgroud)
将ORDER BY查询添加到内部调用也很重要.
| 归档时间: |
|
| 查看次数: |
27339 次 |
| 最近记录: |