使用 Doctrine 迁移数据变得很慢

jj-*_*-aa 2 php doctrine-orm symfony4

我需要将数据从数据库 A 中的一个表导入到数据库 B(同一服务器)中的另一个表,并且我选择了导入它的原则。

我正在使用 Symfony 命令,第一次循环一切正常,只花了 0.04 秒,但随后开始变得越来越慢,几乎需要半个小时......

我正在考虑构建一个 shell 脚本来调用这个 Symfony 命令并给出偏移量(我手动尝试过并保持相同的速度)。这是在 docker 服务中运行,php 服务大约是 100% CPU,但是 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

mal*_*rzm 5

如果花费的时间flush每隔一段时间就变得更长,flush那么您就忘记了clear实体管理器(对于批处理作业,这应该在 之后发生flush)。原因是您不断在实体管理器中累积实体,并且在每次提交期间 Doctrine 都会检查每一个实体是否有更改(我假设您正在使用默认更改跟踪)。

我需要将数据从数据库 A 中的一个表导入到数据库 B(同一服务器)中的另一个表,并且我选择了导入它的原则。

除非您有一些与添加用户相关的复杂逻辑(即应用程序事件,应用程序另一端发生的事情,基本上需要执行一些其他 PHP 代码),否则您的选择很糟糕 - Doctrine 不是为批处理而设计的(虽然如果你真的知道自己在做什么的话它可以做得很好)。对于“简单”迁移,最好的选择是使用 DBAL。