2012-12-14 70 views
2

摘要:哪個更快:更新/刷新實體列表,還是在每個實體上運行查詢構建器更新?Doctrine 2查詢構建器vs實體持久性能

在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時,無論如何,我們都會在開發者分析器中獲得SQL時間。客戶無論如何都決定他們需要querybuilder路由。更新/回滾方法完美。 – mogoman

+0

好吧,無論如何你都歡迎:) – manix