RailsのActiveRecordのメソッドであるfind_each、find_in_batchesとprimary_keyの備忘録。両メソッドの詳しい説明に関しては参考URLを参照してくださいー。

まずはコードリーディングから。find_each、find_in_batchesともにin_batchesを呼び出してクエリ発行&ブロック実行をしています。

挙動としては以下の3つのコードに着目すればOKです

  • relation = relation.reorder(batch_order).limit(of)
  • primary_key_offset = ids.last
  • batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))

※yielded_relationはload_records(records)でrecordsを設定しているのでto_aでレコード抽出時にSQLは発行されない。

ざっくり説明すると

  1. relationでlimit(処理するチャンクのレコード数)を指定してクエリを発行
  2. 次のチャンクは前のチャンクの最後のprimary_keyの値より大きいprimary_keyのレコードを取得

という流れになっています。

例えばbatch_sizeパラメータを10にすると以下のようなSQLが逐次発行され、SQLの結果をActiveRecordのArrayに格納してブロック内の処理が実行されます。

primary_keyをモデルで設定していないケース(例えばMySQLのパーティショニングで複合PRIMARY KEYを使わざるを得ないなど)でfind_each、find_in_batchesを使いたい場合は、self.primary_key=によって主キーを明示的に設定する必要があります。ただし、文字通りprimary_keyなのでユニークでないと、primary_key_offsetの部分でうまくレコードが抽出できません。

参考URL