最近上线的Feature都需要进行数据迁移,在Rails中有三种比较好的数据批处理方式。
1. find_each
find_each方法,接收start, finish, batch_size
等参数,默认每次查询1000条数据。
循环对象是单一实例,方便根据实例进行不同的处理逻辑。
e.g.
Person.find_each do |person|
person.do_awesome_stuff
end
Person.where("age > 21").find_each do |person|
person.party_all_night!
person.drink_much! if person.male?
end
但是需要注意的是,find_each
批量处理,实际上是进行数据偏移从而批量获取数据的,从SQL上理解,就是LIMIT + OFFSET
。
而默认的查询方式是根据ID进行查询和数据偏移的,若批量处理的数据过多,且ID主键在较大偏移时查询过慢,在Mysql中可以强制find_each
使用特定索引,加快查询速度。
使用方式如下:
from("#{self.table_name} USE INDEX(#{index})")
e.g.
User.from('users USE INDEX(index_users_on_xxx)').where(xxx).find_each do |user|
# any logic
end
2. find_in_batches
find_in_batches
方法与find_each
类似, 而且find_each
方法也是基于find_in_batches
实现的,其也接收start, finish, batch_size
等参数,但是其处理对象是一批实例组成的数组,当处理对象的行为一致、可以一次性批量处理时,使用find_in_batches
是个不错的选择。
e.g.
Person.where("age > 21").find_in_batches do |group|
sleep(50) # Make sure it doesn't get too crowded in there!
group.each { |person| person.party_all_night! }
end
3. in_batches
find_in_batches
是基于in_batches
方法实现的,
in_batches方法,接收of, start, finish, load
等参数,返回ActiveRecord::Relation
对象,因此我们可以使用很多作用在ActiveRecord::Relation
对象上的方法,非常的方便。
e.g.
Person.where("age > 21").in_batches do |relation|
relation.delete_all
sleep(10) # Throttle the delete queries
end
FYI: