如何在使用Illuminate插入多个大查询时避免“Allowed memory size of ... bytes exhausted”错误?
如何在使用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()
。
伪代码如下:
- 以下代码按预期工作:
for (多次) { DB::getPdo()->exec('一个大型的插入到...的查询'); }
每次插入后,内存使用量保持在大约11 MB。
- 以下代码会抛出内存耗尽异常
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
运行代码。
当使用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