Laravel / Eloquent内存泄漏重复检索相同的记录
我正在尝试编写一个laravel函数,它可以从一个数据库中获取大量记录(100,000+)并将其放入另一个数据库中。 为此,我需要查询我的数据库并查看用户是否已经存在。 我反复称这个代码:
$users = User::where('id', '=', 2)->first();
然后在那之后发生了几百次,我用完了内存。 所以,我使用了所有可用内存的极简例子,它看起来像这样:
<?php
use IlluminateConsoleCommand;
class memoryleak extends Command
{
protected $name = 'command:memoryleak';
protected $description = 'Demonstrates memory leak.';
public function fire()
{
ini_set("memory_limit","12M");
for ($i = 0; $i < 100000; $i++)
{
var_dump(memory_get_usage());
$this->external_function();
}
}
function external_function()
{
// Next line causes memory leak - comment out to compare to normal behavior
$users = User::where('id', '=', 2)->first();
unset($users);
// User goes out of scope at the end of this function
}
}
这个脚本的输出(由'php artisan command:memoryleak'执行)看起来像这样:
int(9298696)
int(9299816)
int(9300936)
int(9302048)
int(9303224)
int(9304368)
....
int(10927344)
int(10928432)
int(10929560)
int(10930664)
int(10931752)
int(10932832)
int(10933936)
int(10935072)
int(10936184)
int(10937320)
....
int(12181872)
int(12182992)
int(12184080)
int(12185192)
int(12186312)
int(12187424)
PHP Fatal error: Allowed memory size of 12582912 bytes exhausted (tried to allocate 89 bytes) in /Volumes/Mac OS/www/test/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 275
如果我注释掉“$ users = User :: where('id','=',2) - > first();” 那么内存使用率保持稳定。
有没有人有任何见解,为什么这条线会使用这样的记忆,或知道一个更聪明的方法来实现我想要做的?
感谢您的时间。
我重新创建了你的脚本,并通过调试器遍历它,因为我无法理解哪种可怕的东西会导致这种类型的内存问题。 当我走过时,我碰到了这个问题:
// in IlluminateDatabaseConnection
$this->queryLog[] = compact('query', 'bindings', 'time');
看起来你在Laravel中运行的每个查询都存储在一个持久日志中,这说明了每次查询后你日益增加的内存使用情况。 就在上面,是以下行:
if ( ! $this->loggingQueries) return;
多一点挖掘确定默认情况下loggingQueries
属性设置为true,并且可以通过disableQueryLog
方法更改,这意味着,如果您调用:
DB::connection()->disableQueryLog();
在你要执行所有查询之前,你不会看到不断增加的内存使用量; 它根据您的示例代码运行我的测试时解决了问题。 完成后,如果您不想影响可以调用的其他应用程序
DB::connection()->enableQueryLog();
到可重新记录。
我不能说为什么它不释放记忆。 您最好的选择是遵循代码并了解它是如何做的。 或问泰勒。
至于你可以做的其他事情:
缓存查询如果您一遍又一遍地调用相同的查询,那么请使用查询缓存。 这与向查询添加->remember($time_to_cache)
一样简单。
让DBMS做所有的努力。 理想情况下,你只需要insert into select
语句中insert into select
一个内容,但是当你跨越数据库时会变得毛骨悚然。 取而代之的是,批处理select和insert查询,以便减少对数据库的调用并创建更少的对象。 这将更多的负担转移到了数据库管理系统上,这对于这些类型的任务可以说是更有效。
上一篇: Laravel / Eloquent memory leak retrieving the same record repeatedly
下一篇: Django data migration when changing a field to ManyToMany