Большая база данных - медленный запрос доктрины даже с индексом - PullRequest
0 голосов
/ 12 декабря 2018

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

В примере файла CSV, содержащего только 1000 записей, это занимает 16 секунд без индекса и 8 секунд с индексом (MacBook 3Ghz - 16 ГБ памяти).Интуиция подсказывает мне, что это довольно медленно и должно быть выполнено менее чем за 1 секунду, особенно с индексом.

Индекс установлен для столбца электронной почты.

Мой код:

$ssList = $this->em->getRepository(EmailList::class)->findOneBy(["id" => 1]);    

foreach ($csv as $record) {
     $subscriber_exists = $this->em->getRepository(Subscriber::class)
        ->findOneByEmail($record['email']);

    if ($subscriber_exists === NULL) {
        $subscriber = (new Subscriber())
            ->setEmail($record['email'])
            ->setFirstname($record['first_name'])
            ->addEmailList($ssList)
        ;

        $this->em->persist($subscriber);
        $this->em->flush();
    }
}

Мой вопрос:

Как я могу ускорить этот процесс?

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Как сказал Сид, переместите flush () за пределы цикла или поместите счетчик пакетов внутри цикла и выполняйте очистку внутри него только через определенные промежутки времени

$batchSize = 1000;
$i = 1;
foreach ($csv as $record) {
     $subscriber_exists = $this->em->getRepository(Subscriber::class)
        ->findOneByEmail($record['email']);

    if ($subscriber_exists === NULL) {
        $subscriber = (new Subscriber())
            ->setEmail($record['email'])
            ->setFirstname($record['first_name'])
            ->addEmailList($ssList)
        ;

        $this->em->persist($subscriber);
        if (  ($i % $batchSize) === 0) {
            $this->em->flush();
        }
        $i++;
    }
}
$this->em->flush();

Или, если это все еще медленно, вы можетезахватите Соединение $this->em->getConnection() и используйте DBAL, как указано здесь: https://www.doctrine -project.org / projects / doctrine-dbal / en / 2.8 / reference / data-retrieval-and-манипуляции.html # insert

0 голосов
/ 12 декабря 2018

Использовать ЗАГРУЗИТЬ ИНФИЛЬ ДАННЫХ .

ЗАГРУЗИТЬ ИНФИЛЬ ДАННЫХ имеет IGNORE и REPLACE опций для обработки дубликатов, если вы установите UNIQUE KEY или PRIMARY KEY в столбце email.

Посмотрите на настройки , чтобы ускорить импорт.

...