Миграция данных с помощью Doctrine становится медленной - PullRequest
0 голосов
/ 17 октября 2018

Мне нужно импортировать данные из одной таблицы в db A в другую таблицу в db B (на том же сервере), и я выбрал доктрину для ее импорта.

Я использую команды Symfony и всехорошо для первого цикла, просто тратит 0,04 секунды, но затем начинает становиться все медленнее и медленнее и занимает почти полчаса ...

Я собираюсь создать сценарий оболочки для вызова этой команды Symfony, дающейсмещение (я пробовал вручную и сохраняет ту же скорость).Это выполняется в службе Docker, а служба php занимает около 100% ЦП, однако служба mysql составляет 10%

Здесь часть сценария:

class UserCommand extends Command
{
    ...
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $container = $this->getApplication()->getKernel()->getContainer();
        $this->doctrine = $container->get('doctrine');
        $this->em = $this->doctrine->getManager();
        $this->source = $this->doctrine->getConnection('source');

        $limit = self::SQL_LIMIT;
        $numRecords = 22690; // Hardcoded for debugging
        $loops = intval($numRecords / $limit);
        $numAccount = 0;
        for ($i = 0; $i < $loops; $i++){

            $offset = self::SQL_LIMIT * $i;
            $users = $this->fetchSourceUsers($offset);

            foreach ($users as $user) {
                try{

                    $numAccount++;
                    $this->persistSourceUser($user);
                    if (0 === ($numAccount % self::FLUSH_FREQUENCY)) {
                        $this->flushEntities($output);
                    }

                } catch(\Exception $e) {
                    //
                }
            } 
        }
        $this->flushEntities($output);
    }

    private function fetchSourceUsers(int $offset = 0): array
    {
        $sql = <<<'SQL'
        SELECT email, password, first_name
        FROM source.users
        ORDER by id ASC LIMIT ? OFFSET ?
SQL;

        $stmt = $this->source->prepare($sql);
        $stmt->bindValue(1, self::SQL_LIMIT, ParameterType::INTEGER);
        $stmt->bindValue(2, $offset, ParameterType::INTEGER);
        $stmt->execute();
        $users = $stmt->fetchAll();

        return $users;
    }
}

1 Ответ

0 голосов
/ 19 октября 2018

Если время, необходимое для flush, становится длиннее всех остальных flush, то вы забыли clear диспетчер сущностей (что для пакетных заданий должно происходить после flush).Причина в том, что вы продолжаете накапливать сущности в менеджере сущностей, и во время каждой фиксации Doctrine проверяет все изменения на наличие изменений (я полагаю, вы используете отслеживание изменений по умолчанию).

Мне нужно импортировать данныеиз одной таблицы в db A в другую таблицу в db B (тот же сервер), и я выбрал доктрину для ее импорта.

Если у вас нет сложной логики, связанной с добавлением пользователей (например, события приложения,что-то происходит на другой стороне приложения, в основном требуется какой-то другой код PHP для выполнения), тогда вы выбрали плохо - Doctrine не предназначен для пакетной обработки (хотя он может прекрасно работать, если вы действительно знаю, что ты делаешь).Для «простой» миграции лучшим выбором будет использование DBAL.

...