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

时间:2014-08-21 19:22:13

标签: php mysql symfony doctrine-orm innodb

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

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

然后我继续迭代这些行中的每一行并在另一个数据库中执行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();

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

我已经读过,对于做大型插入的innodb表,你应该禁用foreign_key_checks和unique_checks,但我不知道如何为一个教义事务插入执行此操作。

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

状态

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

$maxResults = 10000;
$index = 470000;

执行选择需要97秒,导入需要173。

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

有趣

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

1 个答案:

答案 0 :(得分:4)

Doctrine跟踪工作单元中所有检索到的实体。每次刷新原则都将查找实体更改,以确定要构造的INSERT语句。当工作单元规模增长时,一切都会以指数减速。 您必须在entityManager上调用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();
});