find_each と find_in_batches と in_batches の違い

## find_each

[Railsドキュメント](https://railsdoc.com/page/find_each)
[github](https://github.com/rails/rails/blob/984c3ef2775781d47efa9f541ce570daa2434a80/activerecord/lib/active_record/relation/batches.rb#L68)

### 説明
分割してレコードを取得して1件ずつ処理
デフォルトでは1000件ずつ処理 大きなデータをもつモデルなどを処理する時に使う
内部的には、find_in_batchesを使っており、戻り値の配列に対してeachを実行することで1レコードずつ返している
そのため、使い方はeachと全く同じ

### ソースコード

```rb
    def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block)
      if block_given?
        find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
          records.each(&block)
        end
      else
        enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
          relation = self
          apply_limits(relation, start, finish, order).size
        end
      end
    end
```



## find_in_batches

[Railsドキュメント](https://railsdoc.com/page/find_in_batches)
[github](https://github.com/rails/rails/blob/984c3ef2775781d47efa9f541ce570daa2434a80/activerecord/lib/active_record/relation/batches.rb#L128)

### 説明
分割してレコードを取得して処理
デフォルトで1000件ずつ処理
配列として返ってくる
内部的には、in_batchesを使っており、戻り値を配列に変換したものを呼び出し側のブロック引数として渡している

### ソースコード

```rb
    def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
      relation = self
      unless block_given?
        return to_enum(:find_in_batches, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
          total = apply_limits(relation, start, finish, order).size
          (total - 1).div(batch_size) + 1
        end
      end

      in_batches(of: batch_size, start: start, finish: finish, load: true, error_on_ignore: error_on_ignore, order: order) do |batch|
        yield batch.to_a
      end
    end
```


## in_batches

[Railsドキュメント](https://railsdoc.com/page/in_batches)
[github](https://github.com/rails/rails/blob/984c3ef2775781d47efa9f541ce570daa2434a80/activerecord/lib/active_record/relation/batches.rb#L204)

### 説明
分割してレコードを取得して処理
デフォルトで1000件ずつ処理
呼び出し側のブロック引数として、バッチサイズ単位のActiveRecord::Relationオブジェクトを返す


### ソースコード

```rb
    def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: :asc)
      relation = self
      unless block_given?
        return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
      end

      unless [:asc, :desc].include?(order)
        raise ArgumentError, ":order must be :asc or :desc, got #{order.inspect}"
      end

      if arel.orders.present?
        act_on_ignored_order(error_on_ignore)
      end

      batch_limit = of
      if limit_value
        remaining   = limit_value
        batch_limit = remaining if remaining < batch_limit
      end

      relation = relation.reorder(batch_order(order)).limit(batch_limit)
      relation = apply_limits(relation, start, finish, order)
      relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
      batch_relation = relation

      loop do
        if load
          records = batch_relation.records
          ids = records.map(&:id)
          yielded_relation = where(primary_key => ids)
          yielded_relation.load_records(records)
        else
          ids = batch_relation.pluck(primary_key)
          yielded_relation = where(primary_key => ids)
        end

        break if ids.empty?

        primary_key_offset = ids.last
        raise ArgumentError.new("Primary key not included in the custom select clause") unless primary_key_offset

        yield yielded_relation

        break if ids.length < batch_limit

        if limit_value
          remaining -= ids.length

          if remaining == 0
            # Saves a useless iteration when the limit is a multiple of the
            # batch size.
            break
          elsif remaining < batch_limit
            relation = relation.limit(remaining)
          end
        end

        batch_relation = relation.where(
          predicate_builder[primary_key, primary_key_offset, order == :desc ? :lt : :gt]
        )
      end
    end
```

## 参考

https://railsdoc.com/page/find_each

https://railsdoc.com/page/find_in_batches

https://railsdoc.com/page/in_batches

https://api.rubyonrails.org/v7.1.3.4/classes/ActiveRecord/Batches.html