2012-12-14 4 views
2

요약 : 엔티티 목록을 업데이트/플러시하거나 각각에 대해 쿼리 빌더 업데이트를 실행하는 것이 더 빠릅니까?Doctrine 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) 결과적으로 컬렉션이 필요하다는 것을 염두에 두어야 할 더 좋은 방법이 있습니까?

메모리에있는 결과 집합을 정렬하는 옵션이 아니므로 데이터베이스 수준에서 수행해야합니다. 실제 문은 5 개의 orderbys가있는 10 개의 테이블 조인입니다.

답변

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; 
    } 
} 

당신의 주요 교리 구성에서 당신은 사용할 수 있습니다 : 대답에 대한

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

감사합니다. 우리는 Symfony 2.1을 사용하면서 dev 프로파일 러에서 SQL 시간을 얻습니다. 고객이 어쨌든 querybuilder 경로를 원한다고 결정했습니다. 업데이트/롤백 방법이 완벽하게 작동합니다. – mogoman

+0

음, 어쨌든 환영합니다 :) – manix

관련 문제