find_in_batchesとupdate_allで大量のレコードを分割処理する
最近はバックエンドの処理を捌く場合に、Railsを意識してるとなかなかパフォーマンスが出なかったのが、
find_in_batchesとupdate_allの組み合わせで意外とパフォーマンスが出たので、メモメモ。
今回の件は、かなりデータ数が多くなりすぎて絞り込んでもLockしてる時間が長すぎる場合に有効。
普通のupdate_all
Model.update_all("value = (a * 0.1) + ( b * 0.2)")
上記はupdate_allで処理すると全件もしくはある程度の絞り込みができるが、当然ながらLockされてる時間を考えると厳しい場合がある。
普通のfind_in_batches
Model.find_in_batches(:batch_size => 5000, ) do |models| Model.transaction do models.each do |model| model.value = model.a * 0.1 + model.b * 0.2 model.save! end end end
上記の場合はコミットは5000件でやるけど、UPDATE文が1件ずつになるから件数多いと時間がかかる。
find_in_batches と update_all を組み合わせる
Model.find_in_batches(:batch_size => 5000) do |models| Model.update_all("value = (a * 0.1) + ( b * 0.2)", ["id in (?)", models.map{|m|m.id}]) end
上記のようにキーを条件に大量に投入することで、件数指定でupdateをかける。
レコード数が多くなったときに利用してみると効果的。