如何在使用Illuminate插入多个大查询时避免“Allowed memory size of ... bytes exhausted”错误?

5 浏览
0 Comments

如何在使用Illuminate插入多个大查询时避免“Allowed memory size of ... bytes exhausted”错误?

如何在不遇到内存问题的情况下使用Laravel的MyModel::insert()DB::insert()方法来处理大型SQL查询?

我试图执行大约500次插入,每次插入1000个项目。

如果每次使用查询构建器将项目数组转换为SQL,将会非常方便。然而,重复使用MyModel::insert()DB::insert()会导致内存耗尽。

唯一的低内存解决方法是将数组转换为SQL,并使用DB::statement()DB::getPdo()->exec()

伪代码如下:

  1. 以下代码按预期工作:

for (多次) {
  DB::getPdo()->exec('一个大型的插入到...的查询');
}

每次插入后,内存使用量保持在大约11 MB。

  1. 以下代码会抛出内存耗尽异常

DB::disableQueryLog();
for (多次) {
  MyModel::insert($large_array);
}

前几次插入时内存使用量也是11 MB,但随着循环的迭代次数增加,内存使用量迅速增长,最终达到1 GB。

根据https://stackoverflow.com/a/18776710/17981656上的建议,我禁用了查询日志(DB::disableQueryLog()),但没有帮助。

环境:

Laravel 8.83.9

PHP 8.1

macOS 12.3.1

我使用php artisan serve运行代码。

0
0 Comments

当使用Illuminate进行插入多个大查询时,可能会出现"Allowed memory size of ... bytes exhausted"的错误。这个问题的出现原因是由于查询日志和事件分发器导致的内存泄漏。为了解决这个问题,可以禁用查询日志和事件分发器,并在插入大查询之前进行设置。下面是解决方法的代码示例:

DB::disableQueryLog();
$dispatcher = DB::connection()->getEventDispatcher();
DB::connection()->unsetEventDispatcher();
for (many times) {
    MyModel::insert($large_array);
}
DB::enableQueryLog();
DB::connection()->setEventDispatcher($dispatcher);

更多详细信息和讨论可以参考资源链接:Query builder memory leak on large insert #27539

0