Массовая гидратация Symfony из одного хранилища в другое
У меня есть следующий код, который выполняется нормально, но это занимает слишком много времени... Есть ли способ, которым я могу optomize это с createQueryBuilder и методы обновления?
вот текущая функция:
private function getCsv()
{
$file = 'Diva_tarif.csv';
Message::write("Retriving $file", 3);
$file = $this->root_data . $file;
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder(';')]);
$counter = 0;
$batch_size = 30;
if (($handle = fopen($file, 'r')) !== false) {
$header = fgets($handle);
while (($line = fgets($handle)) !== false) {
$line = $serializer->decode($header . $line, 'csv');
$repo = $this->em->getRepository(Article::class);
if(isset($line['DOS'])){
$counter ++;
$arts = $repo->findBy(array('dos' => $line['DOS'], 'ref' => $line['REF']));
$used_metas = [
'TACOD',
'VENUN',
'DEV',
'PUB',
'ALZTXREMMAX',
'ALZTXREMMAXLALPHA',
];
foreach($arts as $art){
foreach ($used_metas as $metakey ) {
$meta_obj = new ArticleMeta();
$meta_obj->setName($metakey);
$meta_obj->setValue($line[$metakey]);
$meta_obj->setArticle($art);
$this->em->persist($meta_obj);
}
}
if (($counter % $batch_size) === 0) {
$this->em->flush();
$this->em->clear();
}
if(($counter % 500) == 0){
Message::write("$counter lines added", 4);
}
}
}
Message::write("$counter lines added", 4);
Message::write("Done", 3);
$this->em->flush();
$this->em->clear();
fclose($handle);
}
}
Цель состоит в том, чтобы получить Article и назначить новые значения ArticleMeta. Любая идея?
1 ответ
Вы могли бы использовать CsvEncoder
непосредственно без Сериализатора, вы используете декодирование без денормализации.
Я различаю 2 способа улучшить выступления
Без изменения кода
Вы должны индексировать пару ref-dos
в вашу базу данных, это действительно увеличит время запроса.
Но время выполнения вашего скрипта будет расти с увеличением количества строк вашего файла.
Один большой запрос
Вы можете один раз проанализировать ваш файл, извлечь все dos
а также ref
, а затем построить массив с парой ref-dos
,
Пример: [ABCD-1234
, BCDE-2345
,...]
После этого вы можете сделать ONE
большой запрос к вашей базе данных, и избегайте одного запроса / строки, что IMO очень много времени.
Этот способ меньше связан с количеством строк, потому что вы обращаетесь к базе данных один раз.
Таким образом, ИМО является лучшим
Кроме того, вы можете объявить $used_metas
а также $repo
вне времени.
Вы уже используете пакетную очистку + очистку менеджера сущностей, это хороший способ при вставке многих сущностей с помощью Doctrine.
Если вы действительно хотите идти быстро, вы можете использовать сырой SQL и избежать гидратации сущности доктрины. Но я не рекомендую тебе так