Doctrine 2 → Падение производительности при импорте данных
Не в первом проекте уже сталкиваюсь с ситуацией, когда при импорте данных при помощи ORM Doctrine 2 происходит падение производительности с увеличением количества импортируемых данных. Вот и сейчас проявилась данная особенность, а заодно и обнаружилось решение, которым спешу поделиться :)
Небольшое вступление. Переписываю один сайт с некой CMS на более-менее человеческий фреймворк, а заодно разбираю ту кашу, которая образовалась внутри базы данных (из-за того, что прежним разработчикам неоднократно приходилось прикручивать функционал, на который CMS-ка, естественно, не была рассчитана изначально). Пишу определённые SQL-запросы, которые вытягивают информацию в нужной мне форме из старой БД и складывают её в CSV-файлы, из которых впоследствии эти же данные переносятся доктриной в новую БД.
На последнем этапе как раз и наблюдается неприятное явление. Первые порции данных в цикле импортируются быстро, а потом становится заметно, что скорость всё падает и падает.
Вывешу скриншот из серии БЫЛО и СТАЛО, остальное под катом...
Выше результат в секундах. До и после метода clear(). Тут, собственно, и писать уже почти нечего. Приведу код и пару комментариев.
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php
namespace Hypersoft\UltraBundle\Services;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Symfony\Component\Console\Output\OutputInterface;
use Hypersoft\UltraBundle\Entity\Tag;
//bla-bla-bla
class CsvReader
{
protected $doctrine;
protected $em;
/**
* @param Registry $doctrine
*/
public function __construct(Registry $doctrine)
{
$this->doctrine = $doctrine;
$this->em = $doctrine->getManager();
$this->em->getConfiguration()
->setSQLLogger(null);
//bla-bla-bla
}
//bla-bla-bla
/**
* @param string $filename
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return array
*/
public function importTags($filename, OutputInterface $output)
{
$dataArray = $this->readFile($filename);
//bla-bla-bla
foreach ($dataArray as $item) {
$tag = new Tag();
//bla-bla-bla
$this->em->persist($tag);
$this->em->flush();
$output->writeln('insert tag ID = ' . $tag->getId());
$this->em->clear();
}
return $dataArray;
}
}
|
Самое интересно происходит в строках, помеченных более светлым фоном. Это строки 22-23, где происходит отключение логгера и строка 52, которая и позволила ускориться.
Выключение SQL-логгера не даёт сколько-нибудь заметного прироста производительности, зато уменьшает потребление памяти. А метод clear вычищает UnitOfWork от всевозможной подноготной требухи, собираемой доктриной в процессе работы, в частности, будут отсоединяться объекты, управляемые на данный момент EntityManager-ом (что тоже нужно иметь в виду).
Комментарии