【问题标题】:Doctrine 2 query builder vs entity persist performanceDoctrine 2 查询构建器与实体持久性能
【发布时间】:2012-12-14 16:26:13
【问题描述】:

总结:哪个更快:更新/刷新实体列表,还是在每个实体上运行查询生成器更新?

我们在Doctrine ORM(2.3版)中有以下情况。

我们有一张像这样的表

cow
wolf
elephant
koala

我们想使用此表对虚构农场的报告进行排序。问题是用户希望客户订购动物(例如考拉、大象、狼、牛)。现在存在使用 CONCAT 或 CASE 为 DQL 添加权重的可能性(例如 0002wolf、0001elephant)。以我的经验,这要么很难构建,而且当我让它工作时,结果集是一个数组而不是一个集合。

因此,为了解决这个问题,我们为每条记录添加了一个“权重”字段,并且在运行选择之前,我们为每条记录分配了一个权重:

$animals = $em->getRepository('AcmeDemoBundle:Animal')->findAll();

foreach ($animals as $animal) {
    if ($animal->getName() == 'koala') {
        $animal->setWeight(1);
    } else if ($animal->getName() == 'elephant') {
        $animal->setWeight(2);
    }
    // etc
    $em->persist($animal);
}
$em->flush();

$query = $em->createQuery(
    'SELECT c FROM AcmeDemoBundle:Animal c ORDER BY c.weight'
);

这非常有效。为了避免竞争条件,我们在事务块中添加了这个:

$em->getConnection()->beginTransaction();

// code from above

$em->getConnection()->rollback();

这更加强大,因为它可以处理生成相同报告的多个用户。或者,可以像这样对实体进行加权:

$em->getConnection()->beginTransaction();
$qb = $em->createQueryBuilder();
$q = $qb->update('AcmeDemoBundle:Animal', 'c')
            ->set('c.weight', $qb->expr()->literal(1))
            ->where('c.name = ?1')
            ->setParameter(1, 'koala')
            ->getQuery();
$p = $q->execute();

$qb = $em->createQueryBuilder();
$q = $qb->update('AcmeDemoBundle:Animal', 'c')
            ->set('c.weight', $qb->expr()->literal(2))
            ->where('c.name = ?1')
            ->setParameter(1, 'elephant')
            ->getQuery();
$p = $q->execute();

// etc

$query = $em->createQuery(
    'SELECT c FROM AcmeDemoBundle:Animal c ORDER BY c.weight'
);
$em->getConnection()->rollback();

问题:

1) 这两个示例中哪一个的性能更好?

2) 考虑到我们因此需要一个集合,是否有第三种或更好的方法来做到这一点?

请记住,这只是一个示例 - 对内存中的结果集进行排序不是一种选择,它必须在数据库级别完成 - 真正的语句是 10 个表连接和 5 个 orderbys。

【问题讨论】:

    标签: doctrine-orm symfony-2.1 doctrine-query


    【解决方案1】:

    最初,您可以使用名为Logging (\Doctrine\DBAL\LoggingProfiler) 的 Doctrine 实现。我知道这不是更好的答案,但至少您可以实施它以便为您拥有的每个示例获得最佳结果。

    namespace Doctrine\DBAL\Logging;
    
    class Profiler implements SQLLogger
    {
        public $start = null;
    
        public function __construct()
        {
        }
    
        /**
         * {@inheritdoc}
         */
        public function startQuery($sql, array $params = null, array $types = null)
        {
            $this->start = microtime(true);
        }
    
        /**
         * {@inheritdoc}
         */
        public function stopQuery()
        {
            echo "execution time: " . microtime(true) - $this->start;
        }
    }
    

    在您的主要 Doctrine 配置中,您可以启用:

    $logger = new \Doctrine\DBAL\Logging\Profiler;
    $config->setSQLLogger($logger);
    

    【讨论】:

    • 感谢您的回答。当我们使用 Symfony 2.1 时,无论如何我们都会在开发分析器中获得 SQL 时间。客户决定无论如何他们都想要查询构建器路线。更新/回滚方法完美运行。
    猜你喜欢
    • 2020-05-18
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2012-07-14
    • 1970-01-01
    相关资源
    最近更新 更多