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
}
Когда я добавляю использование EntityManager::clear()
после 100 записей (вручную или с использованием Ocramius / DoctrineBatchUtils ), запись # 101 завершится ошибкой, поскольку EntityManager очистил всю информацию, а также информацию, необходимую для выполнения следующего вставки. Поэтому, если я очищаю EntityManager, появляется следующее сообщение об ошибке:
[Doctrine \ ORM \ ORMInvalidArgumentException] Новый объект был найден через отношение «Счет-фактура # клиент», который не был настроен для каскадных операций сохранения для объекта: 740. Для решения этой проблемы: либо явно вызовите EntityManager # persist () в этот неизвестный объект или сконфигурированный каскад сохраняют эту связь в отображении, например, @ManyToOne (.., cascade = {"persist"}).
Я также пытался очистить только некоторые объекты (например, EntityManager::clear(ProductCategory::class)
). Я использовал \Doctrine\ORM\EntityManagerInterface::getUnitOfWork
, чтобы получить все классы, управляемые Doctrine, и очистка класса либо не влияла на используемую память, либо вызвала сообщение об ошибке выше («найден новый объект ...»).
Как я могу узнать, куда направляется вся моя память и как я могу улучшить свою логику импорта, чтобы предотвратить этот голод памяти?