数据量大。迭代而不耗尽内存的最佳方法?

sim*_*w16 4 php out-of-memory laravel

使用 Laravel 6 等 Eloquent Collection 类。

所以我有“很多”数据需要处理。大约 5000 行,在获取它时,会生成一个包含 5000 个模型的集合。现在,每个模型可能都有 20 个属性需要读取。

有没有快速的方法来做到这一点?我目前有一个要读取的属性数组,然后像这样设置循环:

\fopen()...

foreach ($models as $model) {
            $row = [];
            foreach ($this->attributes as $attr) {
                $row[] = \data_get($model, $attr);
            }
        
        \fputcsv($fh, $row);
}

\fclose()...
Run Code Online (Sandbox Code Playgroud)

$models是一个 Laravel 集合,由其中创建,EloquentModel::find($ids);其中$ids是整数数组。(来自数据库的 5000 个 ID)

$this指的是包含 foreach 循环的类。attributes除了包含上面代码的函数和只是一个字符串数组的属性之外,这个类中没有其他任何东西。

对于 5000 行,每行循环 20 个属性,这可能需要很长时间来处理,并且在每种情况下,这实际上都会抛出FatalErrorException: Allowed memory size of 134217728 bytes exhausted

那么检索每行属性集的最快方法是什么?我个人想不出比这个嵌套循环更快的循环了。

此外,看到\fputcsv()将每一行写入文件,并且$row变量在每个循环中被覆盖,为什么我仍然得到Allowed memory size exhausted

LazyCollection 是这里的解决方案吗?

谢谢!

Aas*_*aba 9

这将一次处理 200 个块中的模型,从而节省大量内存。

Model::whereIn('id', $ids)->chunk(200, function($models){

      foreach ($models as $model) {
            $row = [];
            foreach ($this->attributes as $attr) {
                $row[] = \data_get($model, $attr);
            }
        
        \fputcsv($fh, $row);
      }
});
Run Code Online (Sandbox Code Playgroud)

  • 我对此不确定,但我认为 $models 已经获得了一些内存,当我们在这里讨论模型实例的集合时,这可能会很大,并且处理此类大数据也需要内存。可能还有其他方法可以提高效率。我现在无法弄清楚任何其他的。上述解决方案有效吗? (2认同)