Rails のループ処理(each, find_each, find_in_batches)

モデルから複数のレコードを取得してループ処理を行う場合の例を紹介します。

each

全レコードを一気に取得し、それらすべてをメモリ上に保存します。メモリが足らないとアプリがフリーズするので、DBから大量のレコードを読み込む場合などは使用を避けましょう。

find_each

レコードを分割(デフォルトは1000件)して取得し、1レコードずつ処理します。ただし、レコードの順序は指定できません。

User.find_each{|user| p user.id }
=> SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1000
1
2
3
.
.
1000

# 次の1000件を取得
=> SELECT "users".* FROM "users" WHERE ("users"."id" > 1000) ORDER BY "users"."id" ASC LIMIT 1000
1001
1002
.
.
2000

分割(バッチ)数を指定する場合は batch_size を指定します。

User.find_each(batch_size: 100){|user| p user.id }
=> SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 100
1
2
3
.
.
100

# 次の100件を取得
=> SELECT "users".* FROM "users" WHERE ("users"."id" > 100) ORDER BY "users"."id" ASC LIMIT 100
101
102
.
.
200

find_in_batches

レコードを分割(デフォルトは1000件)して取得し、配列で処理します。ただし、レコードの順序は指定できません。

User.find_in_batches{|user_array| p user_array.size }
=> SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1000
1000

# 次の1000件を配列で取得
=> SELECT "users".* FROM "users" WHERE ("users"."id" > 1000) ORDER BY "users"."id" ASC LIMIT 1000
1000

分割(バッチ)数を指定する場合は batch_size を指定します。

User.find_in_batches(batch_size: 100){|user_array| p user_array.size }
=> SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 100
100

# 次の100件を取得
=> SELECT "users".* FROM "users" WHERE ("users"."id" > 100) ORDER BY "users"."id" ASC LIMIT 100
100