Массовая гидратация Symfony из одного хранилища в другое - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть следующий код, который выполняется нормально, но это занимает слишком много времени ... Есть ли способ, как я могу это опровергнуть с помощью 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 Ответ

0 голосов
/ 04 сентября 2018

Вы можете использовать CsvEncoder напрямую без Сериализатора, вы используете декодирование без денормализации.

Я различаю 2 способа улучшения производительности

Без изменения кода

Вы должны индексировать пару ref-dos в вашу базу данных, это действительно увеличит время запроса.

Но время выполнения вашего скрипта будет увеличиваться с увеличением количества строк в вашем файле.

Один большой запрос

Вы можете один раз проанализировать ваш файл, извлечь все dos и ref, а затем построить массив с парой ref-dos.

Пример: [ABCD-1234, BCDE-2345, ...]

После этого вы можете сделать ONE большой запрос к вашей базе данных и избежать одного запроса / строки, что IMO занимает очень много времени.

Этот способ меньше связан с количеством строк, потому что вы запрашиваете базу данных один раз.

Таким образом, ИМО является лучшим


Кроме того, вы можете объявить $used_metas и $repo вне времени.

Вы уже используете пакетную очистку + диспетчер сущностей, это хороший способ при вставке многих сущностей с помощью Doctrine.


Если вы действительно хотите идти быстро, вы можете использовать сырой SQL и избежать гидратации сущности доктрины. Но я не рекомендую тебя таким образом

...