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