最好使用 chunkById 而不是 chunk 以避免批量更新時丟失行。使用 chunk 可以在更新行後移動後續查詢的偏移量,導致跳過未處理的行。
例如:
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 行。第二個查詢沒有意識到這一點,因此跳過 100 個未處理的行,因為它仍然使用偏移量。
以上由
詳細解釋
太阮雄
當嘗試使用 Laravel 的 chunk() 方法處理有限數量的行時,我們可能會期望以下程式碼以 2 為一組僅處理 5 個使用者:
$query = \App\Models\User::query()->take(5); $query->chunk(2, function ($users) { // Process users });
但是,這將處理資料庫中的所有用戶,一次兩個。發生這種情況是因為 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中文網其他相關文章!