1. 程式人生 > >Laravel中chunk方法分塊處理資料,update需注意

Laravel中chunk方法分塊處理資料,update需注意

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條件是篩選approved0user然後將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;
}