Laravel chunk 分块 以及存在的一些坑

Laravel chunk分块处理数据 以及存在的一些坑

假设这样的情况: 您有一个大的数据库表(比如10000行或更大的行),并且需要对一列进行更新。但是不只是运行SQL查询,还有很多PHP逻辑。 因此foreach循环可能会占用很多的运行时间,或者遇到默认的30秒脚本限制。下面说说Laravel的解决方案.

例如:

$users = User::all();
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或500个用户的DB表来说,这是很好的解决方式。但是一万呢?十万?百万?这不仅与速度有关,还与存储数据有关—您可能将整个数据库表存储到变量中,可能会耗尽内存。

laravel中: 模型的 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个条目,然后用它们进行更新,然后再选择100个条目,再进行一次更新等等。这意味着在任何情况下都不会有大量的数据从数据库中获取——您处理的是一大块条目,而不是整个表。

但laravel 的chunk()存在以下的坑,避免处理以下的操作: 

User::where('approved', 0)->chunk(100, function ($users) {
  foreach ($users as $user) {
    $user->update(['approved' => 1]);
  }
});

原因:如您正在筛选未经批准的用户,然后批准他们,在下一个块上,当Laravel正在执行另一个数据库查询以获取另一 页 数据时,数据已经在那时更改了,您将丢失一页数据。这意味着你将只处理一半的条目。

所以不要更新会影响初始筛选条件的字段。

 

注意:

laravel chunk操作的方式虽好,但使用的时候注意有个弊端(update时候):他每次操作的是一个数据块而不是整个数据库,会漏掉一些数据,目前好像并没有解决办法,所以用的时候得注意;

laravel chunk原代码如下

public function chunk($count, callable $callback)
    {
        $this->enforceOrderBy();

        $page = 1;

        do {
            // We'll execute the query for the given page and get the results. If there are
            // no results we can just break and return from here. When there are results
            // we will call the callback with the current chunk of these results here.
            $results = $this->forPage($page, $count)->get();

            $countResults = $results->count();

            if ($countResults == 0) {
                break;
            }

            // 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 ($callback($results, $page) === false) {
                return false;
            }

            unset($results);

            $page++;
        } while ($countResults == $count);

        return true;
    }

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值