find_each_with_order

上一篇blog,分析了一下find_each的源码,后来又查了一下解决的办法,这里记录一下找到的几种可以代替find_each的方法。

第一种 先排好序,获取到已经排好序的ids数组,然后对数组分组执行

1
2
3
4
5
6
7
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

第二种 通过指定好数组区间,然后分组获取,原理和方法一相同,代码如下

1
2
3
4
5
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

rails find_each方法源码分析

在项目中我们经常会使用如下代码

1
2
3
Product.all.each do |product|
do_something
end

在实际应该中如果Product表太大,一次读取会把内存占满,Rails为了解决这个问题提供了两个方法,find_each和find_in_batches方法,把记录分成几个批次,因为find_each其实最终就是调用的find_in_batches,所以这里我们以find_in_batches为例。

1
2
3
Product.all.find_in_batches(start: 2000, batch_size: 5000,include: :infos) do |products|
do_something
end

rails项目优化 sql优化

因为项目的表数据量比较大,系统经常因为内存满而卡死,所以对整个rails项目进行了一次简单的优化,其中涉及到了几个比较关键的点,记录下来。假设有个product表,数量在百万级别的。

因为是rails项目所以里面会包含一些rails注意事项,还有一些简单的sql语句优化,水平有限,如果有什么不对的地方,还请邮件联系我。