バッチ更新中の行の欠落を避けるために、chunk の代わりに chunkById を使用することをお勧めします。チャンクを使用すると、行の更新後に後続のクエリのオフセットがシフトされ、未処理の行がスキップされる可能性があります。
例:
Post::where('processed', 0)->chunk(100, function($posts) { foreach($posts as $post) { $post->processed = 1; $post->save(); } });
上記のコードは次のクエリを生成します。
select * from `posts` where `processed` = 0 limit 100 offset 0 select * from `posts` where `processed` = 0 limit 100 offset 100 ...
最初のチャンクは 100 行を更新します。 2 番目のクエリは、これを認識せず、オフセットを引き続き使用するため、未処理の 100 行をスキップします。
上記については
で詳しく説明されています
タイ・グエン・フン
Laravel の chunk() メソッドを使用して限られた数の行を処理しようとすると、次のコードは 2 つのバッチで 5 ユーザーのみを処理すると予想される場合があります。
$query = \App\Models\User::query()->take(5); $query->chunk(2, function ($users) { // Process users });
ただし、これはデータベース内のすべてのユーザーを一度に 2 人ずつ処理します。これは、Laravel の chunk() メソッドがクエリに適用された take() 制限を無視し、すべての行がチャンクで処理されるために発生します。
限られた数の行 (例: 5 ユーザー) のみがチャンクで処理されるようにするために、指定された制限に達した後にチャンキング ループを中断するカスタム インデックス カウンターを実装できます。次のコードはこれを実現します:
class UserProcessor { private int $index = 0; private int $limit = 5; public function process() { $query = \App\Models\User::query(); $query->chunk(2, function ($users) { foreach ($users as $user) { $this->index++; // Process each user here // Example: $user->processData(); if ($this->index >= $this->limit) { // Stop processing after reaching the limit return false; // This will stop chunking } } }); } }
注意
$index と $limit はクラスのプロパティであり、use($index, $limit) でクロージャに渡されるメソッド変数ではありません。これは、 use() 経由で渡された変数が値によってクロージャ オブジェクトにコピーされるためです。結果として、クロージャ内の変更は元の値に影響を与えません。そのため、反復間で変更を適切に更新および追跡するには、それらをクラス プロパティにする必要があります。
以上がLaravel クエリの最適化: データをチャンクする正しい方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。