背景
我需要把一张表的所有数据查询出来,然后逐一查询出来进行逻辑处理。
代码如下:
public function handle()
{
EloquentStoredEvent::query()->cursor()->each(function (EloquentStoredEvent $storedEvent){
// 逻辑处理
$this->info(round(memory_get_usage()/1024/1024, 2).'MB');
});
}
在代码中,我使用了 Eloquent 的 cursor, 他的原理就是使用了 PDO 的 execute 方法,将数据库的结果集放到 php 的内存中,然后通过 php 的生成器 一行一行从结果集 fetch 出来数据转换成 orm 对象。这个比起使用 Eloquent 的 get 更能节约内存开销。
问题
当我执行代码的时候。它会一行行执行
$this->info(round(memory_get_usage()/1024/1024, 2).'MB');
我发现了个问题,假如有 80 万条数据,第一次执行内存占用 962.36MB,后面会慢慢增加,到最后一次执行内存占用 1901.39MB。
那如果有一个脚本需要长时间才能处理完成,你开始观察几分钟可能正常,但是看你过了半个小时它就因为内存不够而运行失败。
找到原因
后面我发现和 PDO::ATTR_EMULATE_PREPARES 有关系,在 Illuminate\Database\Connectors\Connector 默认 PDO::ATTR_EMULATE