我正在尝试使用Doctrine2和Symfony2 fixture包在MySQL数据库中插入大量数据(3万多行)。
我看了the right way to do it。我看到很多关于内存泄漏和Doctrine的问题,但对我来说没有令人满意的答案。通常是Doctrine clear()
函数。
所以,我做了各种各样的形状:
while (($data = getData()) {
$iteration++;
$obj = new EntityObject();
$obj->setName('henry');
// Fill object...
$manager->persist($obj);
if ($iteration % 500 == 0) {
$manager->flush();
$manager->clear();
// Also tried some sort of:
// $manager->clear($obj);
// $manager->detach($obj);
// gc_collect_cycles();
}
}
在flush()
之后,PHP内存仍然很疯狂(我很确定)。事实上,每次刷新实体时,内存都会根据批量大小和实体上升一定量,直到达到致命允许的内存大小耗尽错误。使用非常小的实体,它可以工作,但内存消耗增加太多:几MB而应该是KB。
clear()
,detach()
或调用GC似乎根本没有效果。它只清除一些KB。
我的方法有缺陷吗?我在某处错过了什么吗?这是一个错误吗?
更多信息:
flush()
内存几乎不动; 编辑(部分解决方案):
@qooplmao带来了一个显着降低内存消耗的解决方案,禁用了doctrine sql logger:$manager->getConnection()->getConfiguration()->setSQLLogger(null);
然而,它仍然异常高并且在增加。
答案 0 :(得分:9)
我使用this resource解决了我的问题,正如@Axalix建议的那样。
这是我修改代码的方式:
// IMPORTANT - Disable the Doctrine SQL Logger
$manager->getConnection()->getConfiguration()->setSQLLogger(null);
// SUGGESION - make getData as a generator (using yield) to to save more memory.
while ($data = getData()) {
$iteration++;
$obj = new EntityObject();
$obj->setName('henry');
// Fill object...
$manager->persist($obj);
// IMPORTANT - Temporary store entities (of course, must be defined first outside of the loop)
$tempObjets[] = $obj;
if ($iteration % 500 == 0) {
$manager->flush();
// IMPORTANT - clean entities
foreach($tempObjets as $tempObject) {
$manager->detach($tempObject);
}
$tempObjets = null;
gc_enable();
gc_collect_cycles();
}
}
// Do not forget the last flush
$manager->flush();
最后但并非最不重要的是,当我将此脚本与Symfony数据夹具一起使用时,在命令中添加--no-debug
参数也非常重要。然后内存消耗稳定。
答案 1 :(得分:0)
我发现 Doctrine 在执行期间记录所有 SQL。我建议用下面的代码禁用它,它确实可以节省内存:
use Doctrine\ORM\EntityManagerInterface;
public function __construct(EntityManagerInterface $entity_manager)
{
$em_connection = $entity_manager->getConnection();
$em_connection->getConfiguration()->setSQLLogger(null);
}
答案 2 :(得分:-2)