mysql 提高大型Doctrine查询的性能

e5nqia27  于 2023-01-01  发布在  Mysql
关注(0)|答案(2)|浏览(151)

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

$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。有没有进一步的方法可以优化它?我阅读到的水合在迭代查询时是关闭的,对吗?

nqwrtyyt

nqwrtyyt1#

我在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的结果集不会)。
教条能解决你80%的问题,剩下的20%最好不要教条。
迭代查询时水合是关闭的,我的阅读是否正确?
不能,除非你改变水合模式,你可以通过给iterate()方法传递第二个参数来实现。

a11xaf1n

a11xaf1n2#

理论文档中的示例

$batchSize = 20;
$i = 1;
$q = $em->createQuery('select u from MyProject\Model\User u');
foreach ($q->toIterable() as $user) {
    $user->increaseCredit();
    $user->calculateNewBonuses();
    ++$i;
    if (($i % $batchSize) === 0) {
        $em->flush(); // Executes all updates.
        $em->clear(); // Detaches all objects from Doctrine!
    }
}
$em->flush();

相关问题