🥮

LaravelのchunkとchunkByIdの違いと使い分け

に公開

はじめに 📚

Laravelには、大量のデータを処理する際に便利なメソッドとしてchunkとchunkByIdがあります。
どちらも一定数のレコードを分割して処理するために使われますが、それぞれに特徴や適した用途があります。
両者の違いと適切な使い分けについて、まとめました。

chunkの基本

chunkメソッドは、指定した件数ごとにデータを分割し、クロージャ内で処理を行います。

use App\Models\User;

User::chunk(100, function ($users) {
    $users->each(function ($user) {
        // 各ユーザーに対する処理
        return $user->name;
    });
});

メリット ✅

メモリ消費を抑えながら大量データを処理できる
データ件数が少なくても手軽に使える

デメリット ❌

ORDER BY id ASC が自動的に適用されるため、ID順以外の並び順が必要な場合は適さない
データの途中で変更があると、同じレコードが処理される可能性がある

chunkByIdの基本

chunkByIdメソッドは、IDを基準にデータを分割するため、処理中にデータが変更されても影響を受けにくいという特長があります。

use App\Models\User;

User::where('status', 'active')
    ->chunkById(100, function ($users) {
        $users->each(function ($user) {
            // 各ユーザーに対する処理
            return $user->name;
        });
    }, 'id');

メリット ✅

idを基準に処理するため、途中でデータが変更されても安全
一意のIDを使うことで、データの不整合を防げる

デメリット ❌

idが連番でない場合(例えばUUIDなど)、適用できない場合がある
IDを基準とするため、別のカラムでソートしたい場合には不向き

foreachではなくeachを使う理由 💡

LaravelのCollectionクラスには、eachメソッドが用意されており、foreachと同様にコレクションの各アイテムに対して処理を行います。eachを使う理由は以下の通りです。

コレクションのメソッドと組み合わせやすい eachはCollectionのメソッドで、map、filter、reduceなどの他のコレクション操作と連携が容易です。

遅延実行が可能 コレクション内のデータを遅延実行するため、メモリ使用量を最適化できます。
可読性が向上 コードがより宣言的になり、意図が明確になります。

eachを使用することで、コレクションの処理意図が明確に伝わります。

$users->each(function ($user) {
    // 各ユーザーに対する処理
    return $user->name;
});

より効率的で可読性が高くなります。

使い分けのポイント

メソッド 適したケース
chunk ID順で処理して問題ない、データの変更が少ない場合
chunkById ID順で確実に処理したい、データの変更が頻繁にある場合

パフォーマンス比較 🚀

chunkは単純にオフセットでデータを取得するため、大量データではOFFSETが遅くなる可能性があります。一方、chunkByIdはWHERE id > last_idのように取得するため、インデックスの恩恵を受けやすく、パフォーマンスが向上します。

まとめ

chunkは簡単に使えるが、データ変更に弱い
chunkByIdはデータの変更があっても安全に処理できる
大量データではchunkByIdの方がパフォーマンスが良い場合が多い

Discussion