Doctrine 2查询生成器与实体持久性能

时间:2012-12-14 16:26:14

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

摘要:哪个更快:更新/刷新实体列表,或者在每个实体上运行查询构建器更新?

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

我们有一个看起来像这样的表

cow
wolf
elephant
koala

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

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

$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个订单。

1 个答案:

答案 0 :(得分:0)

最初,您可以使用名为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);