如何使用 Doctrine 2 提高 LARGE 导入的性能

Cha*_*ase 1 php mysql innodb symfony doctrine-orm

我有大约 100 万条记录需要导入。我一直在网上寻找改进和加速这一过程的方法。目前,我的应用程序连接到 1 个数据库,对大约 220 万行的表进行选择,此选择持续大约需要 10-13 秒。我使用此查询选择 10,000 行。

$results = $em->getRepository('...')->createQueryBuilder('x')
              ->where('...')
              ->setFirstResult($index)
              ->setMaxResults($maxResults)
              ->getQuery()
              ->getResult();
Run Code Online (Sandbox Code Playgroud)

然后,我继续迭代每一行,并在另一个数据库中进行 2 次查找,使用这些实体创建一个新实体,并使用事务一次插入所有 10,000 个新实体。

$secondEm->transactional(function($em){
    foreach($results as $result){
        $value1 = $em->getRepository('A')->findOneBy(array('value'=>$result->getValue()));
        $value2 = $em->getRepository('B')->findOneBy(array('value'->$result->getValue()));
        $newEntity = new Entity();
        $newEntity->setValue1($value1)->setValue2($value2);
        $em->persist($newEntity);
    }
    $em->flush();
});
$secondEm->clear();
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是每次后续插入的导入时间都会逐渐变长。前 10,000 个大约需要 60 秒,第二个需要 100 秒,然后从那里开始,每次新插入似乎都会增加大约 5-10 秒。

我读过,对于进行大型插入的 innodb 表,您应该禁用foreign_key_checks 和 unique_checks,但我不知道如何为原则事务插入做到这一点。

任何有关如何禁用这些检查或什至更好的方法来执行此导入的建议将不胜感激。

地位

选择查询现在似乎也在时间上增加。最后一个查询:

$maxResults = 10000;
$index = 470000;
Run Code Online (Sandbox Code Playgroud)

选择花了 97 秒,导入花了 173 秒。

重要 这个过程每个请求发生一次,我有一个 javascript 操作,它将自动提交空白表单,这一切都发生在 POST 上,我意识到这可能会更好地从命令运行,因为它都在同一服务器上,但在那里还有其他方法可以优化这个吗?

有趣的

现在已经插入了大约 650,000 条记录,并且似乎已经趋于平稳。选择查询需要 60-70 秒,导入查询大约需要 170-180 秒,总处理时间为 230-250 秒。

Bra*_*sen 5

Doctrine 会跟踪工作单元中所有检索到的实体。对于每个同花原则,都会查找实体更改以确定INSERT要构建哪些语句。当工作单元大小增长时,一切都会呈指数级下降。您必须调用clear()实体管理器来从内存中删除不再需要的实体。请参阅http://docs.doctrine-project.org/en/2.0.x/reference/batch-processing.html

$secondEm->transactional(function($em){
    foreach($results as $result){
        $value1 = $em->getRepository('A')->findOneBy(array('value'=>$result->getValue()));
        $value2 = $em->getRepository('B')->findOneBy(array('value'->$result->getValue()));
        $newEntity = new Entity();
        $newEntity->setValue1($value1)->setValue2($value2);
        $em->persist($newEntity);
    }
    $em->flush();
    $em->clear();
});
Run Code Online (Sandbox Code Playgroud)