提高大型Doctrine查询的性能

时间:2016-01-23 12:37:06

标签: mysql doctrine-orm symfony

在Symfony3中,我使用Doctrine的QueryBuilder从我的3500万行表中迭代多达500k行:

$query = $this->createQueryBuilder('l')
            ->where('l.foo = :foo')
            ->setParameter('foo', $foo)
            ->getQuery();

$results = $query->iterate();

foreach ($results as $result) {
   $em->clear();
   // My logic using $result[0]
}

在我开始迭代之前,这通常会接近512mb的内存使用量。还有什么方法可以优化这个吗?我是否正确阅读在迭代查询时关闭水合作用?

1 个答案:

答案 0 :(得分:6)

generators我取得了很好的成绩。也许处理结果采用单独的方法可以帮助PHP清理未使用的对象。我不知道你在处理你的记录时做了什么,并且不能保证你会得到相同的结果,但在我的情况下,通过整个脚本执行,内存消耗保持不变:

public function getMyResults($foo)
{
    $query = $this->createQueryBuilder('l')
        ->where('l.foo = :foo')
        ->setParameter('foo', $foo)
        ->getQuery();

    foreach ($query->iterate() as $result) {
        yield $result[0]

        $em->clear();
    }
}

public function processMyResults($foo)
{
    foreach ($this->getMyResults($foo) as $result) {
    }
}

如果这没有帮助,请考虑使用DBALPDO进行查询(两者都使用fetch()方法,以避免一次性获取所有记录)。 Doctrine的迭代器可能会泄漏内存(PDO&#39结果集不应该)。

Doctrine将解决80%的问题。如果没有它,剩下的20%会更好。

  

在阅读迭代查询时关闭水合作用时,我是否正确?

不,除非你改变水合模式。您可以通过a second argument to the iterate() method

来完成