TL; DR:找不到所有针对“ Doctrine ORM导入性能问题”的解决方案,因为EntityManager::clear
还清除了下一批所需的实体。
我遇到了性能问题,因为在执行批处理工作时内存使用率一直在增加。我已经阅读了许多有关此问题的问题和博客文章,但是所有给定的解决方案都使用一个非常简单的示例插入实体,而没有任何集合/关系。内存限制的增加“有所帮助”,但是随着数据库的增长,我现在甚至没有物理内存。
我的导入脚本看起来像这样(非常简化的示例,用一些通用名称替换了我自己的业务逻辑):
$customers = $repo->getCustomers(); //array Customer[]
foreach ($customers as $customer) {
// this line adds about 40kB every time
$country = $customer->getCity()->getCountry();
// while this doesn't add
$city = $customer->getCity();
// tried to use garbage collector, but even this doesn't free memory
unset($country);
$country = null;
gc_collect_cycles();
// insert logic removed for the sake of simplicity
}
当我在100个条目(手动或使用Ocramius/DoctrineBatchUtils)后添加使用EntityManager::clear()
时,条目#101将失败,因为EntityManager清除了所有信息,也包括执行下一次插入操作所需的信息。因此,如果我清除EntityManager,则会出现如下错误消息:
[Doctrine \ ORM \ ORMInvalidArgumentException]通过关系'Invoice#customer'找到了一个新实体,该关系未配置为级联实体的持久性操作:740。解决此问题:显式调用EntityManager#persist()此未知实体或配置级联会在映射中保留此关联,例如@ManyToOne(..,cascade = {“ persist”})。
我还尝试仅清除某些实体(例如EntityManager::clear(ProductCategory::class)
)。我使用\Doctrine\ORM\EntityManagerInterface::getUnitOfWork
来获取由Doctrine管理的所有类,并且清除一个类对已用内存没有影响,或者导致了以上错误消息(“发现新实体...”)。
如何找到所有内存的去向,以及如何改善导入逻辑以防止内存不足?