2

要約: エンティティのリストを更新/フラッシュするのと、それぞれに対してクエリ ビルダーの更新を実行するのとでは、どちらが速いですか?

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 つの例のうち、どちらがより優れたパフォーマンスを発揮しますか?

2)結果としてコレクションが必要であることを念頭に置いて、これを行うための3番目またはより良い方法はありますか?

これは単なる例であることに注意してください。結果セットをメモリ内でソートすることはオプションではありません。データベース レベルで実行する必要があります。実際のステートメントは、5 つの orderby を持つ 10 テーブルの結合です。

4

1 に答える 1

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);
于 2012-12-15T13:15:36.440 に答える