Laravel中chunk方法分塊處理資料,update需注意
阿新 • • 發佈:2019-02-10
在Laravel
框架中我們可以很方便的使用chunk
方法來解決。
來看一個簡單的例子:
$users = User::all();
foreach ($users as $user) {
$some_value = ($user->some_field > 0) ? 1 : 0;
// 一些其他的邏輯
$user->update(['some_other_field' => $some_value]);
}
這段程式碼看起來並沒有什麼不對,但是當資料量很大的時候,情況就不那麼樂觀了,一方面是執行時間,再者要考慮資料儲存時記憶體消耗完。
在Laravel中,應用chunk將資料分塊的方法,可以很好的處理這種問題,下面是應用chunk的程式碼:
User::chunk(100, function ($users) {
foreach ($users as $user) {
$some_value = ($user->some_field > 0) ? 1 : 0;
// might be more logic here
$user->update(['some_other_field' => $some_value]);
}
});
這段程式碼是執行一個100條的資料進行更新,當執行完成後繼續後面的另一百條資料……
也就是說他每次操作的是一個數據塊而不是整個資料庫。
User::chunk(100 , function ($users) {
foreach ($users as $user) {
$some_value = ($user->some_field > 0) ? 1 : 0;
// might be more logic here
$user->update(['some_other_field' => $some_value]);
}
});
需要注意的是:當使用帶篩選的條件的chunk時,如果是自更新,那麼你會漏掉一些資料,接著看程式碼:
User::where('approved', 0)->chunk(100, function ($users) {
foreach ($users as $user) {
$user->update(['approved' => 1]);
}
});
如果要執行上面的程式碼,並不會有報錯,但是where
條件是篩選approved
為0
的user
然後將approved
的值跟新為1
。
在這個過程中,檔第一資料庫的資料被修改後,下一個資料塊的資料將是在被修改後的資料中選出來的,這個時候資料變了,而page也加了1。所以執行結束後,只對資料中一半的資料進行了更新操作。
如果沒有明白的話,我們來看一下chunk的底層實現。還以上面的程式碼為例,假如一共有400條資料,資料被按照100條進行分塊處理。
page = 1: 最開始的時候page為1,選取1-100條資料進行處理;
page = 2: 這時候前一百資料的approved
值全部為1,那麼在次篩選的時候資料將從第101條開始,而這個時候的page=2,那麼處理的資料將是第200-300之前的資料
之後依舊。
public function chunk($count, callable $callback)
{
$results = $this->forPage($page = 1, $count)->get();
while (count($results) > 0) {
// On each chunk result set, we will pass them to the callback and then let the
// developer take care of everything within the callback, which allows us to
// keep the memory low for spinning through large result sets for working.
if (call_user_func($callback, $results) === false) {
return false;
}
$page++;
$results = $this->forPage($page, $count)->get();
}
return true;
}