Тормозят inserts в MongoDB (Doctrine 2 ODM)
Недавно на работе столкнулись с такой проблемой. Необходимо было провести импорт множества сущностей из MySQL в MongoDB. Но вот незадача, первые 200 объектов импортировались нормально, а потом скорость начала асимптотически падать стремясь к нулю.
Задача в принципе была простая, даже впилил в консольную команду Symfony 2 прогресс-бар. Кстати хорошая штука. Позволяет прикидывать как скорость процесса, так и общий прогресс. Вот он то мне и помог понять, что что-то не то. Я уже начал грешить на php, запиливать многопоточную обработку, когда коллега сказал, что надо копать не в сторону php как такового, а в сторону MongoDB и Doctrine.
Решилось всё простою. Надо было в конце итреации цикла делать
1 |
$dm->clear(); |
который собственно очищает UnitOfWork, все мета-данные и т.д. Вот кстати его код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/** * Clears the UnitOfWork. * * @param string $documentName if given, only documents of this type will get detached */ public function clear($documentName = null) { if ($documentName === null) { $this->identityMap = $this->documentIdentifiers = $this->originalDocumentData = $this->documentChangeSets = $this->documentStates = $this->scheduledForDirtyCheck = $this->documentInsertions = $this->documentUpdates = $this->documentDeletions = $this->collectionUpdates = $this->collectionDeletions = $this->extraUpdates = $this->parentAssociations = $this->orphanRemovals = array(); if ($this->commitOrderCalculator !== null) { $this->commitOrderCalculator->clear(); } } else { $visited = array(); foreach ($this->identityMap as $className => $documents) { if ($className === $documentName) { foreach ($documents as $document) { $this->doDetach($document, $visited, true); } } } } if ($this->evm->hasListeners(Events::onClear)) { $this->evm->dispatchEvent(Events::onClear, new Event\OnClearEventArgs($this->dm, $documentName)); } } |
После этого скорость вставок падать перестала, и то что занялбо у меня целые выходные выполнилось за 3 минуты 🙂
А зачем сюда доктрина? Простейший скрипт с batchInsert будет еще производительней
Да, Олег. Иногда так и делаем. Но к хорошему быстро привыкаешь 🙂
🙂
Также не следует забывать, что доктрайн пишет еще и все запросы в лог (Symfony 2).
Да, это если есть серви ‘logger’. Но, можно выключить это для продакшена.