2015-06-18 57 views
0

假設我有6000個值,並且我正在執行一個for循環,並使用Symfony2 + Doctrine執行INSERTUPDATE操作,這是執行這些語句的最佳/正確方法並保持良好的性能水平?Doctrine2性能:插入/更新多行

首先

for ($i = 0; $i < 6000; $i++) { 
    // SELECT HERE - need to find if Territory already exists 
    $entTerritory = $em->getRepository('PDOneBundle:Territory')->findOneBy(array('veeva_territory_id' => $soqlObj2['records'][$i]['Id'])); 

    if (!$entTerritory) { 
     // if there is no territory, then we add 
     $newTerritory = new Entity\Territory(); 

     // we set the values from veeva 
     if ($soqlObj2['records'][$i]['Id'] !== null || $soqlObj2['records'][$i]['Id'] !== "") { 
      $newTerritory->setVeevaTerritoryId($soqlObj2['records'][$i]['Id']); 
      $newTerritory->setName($soqlObj2['records'][$i]['Name']); 

      $em->persist($newTerritory); 
      $em->flush(); // ---> FLUSH HERE 
     } 

     $terrArr[] = $newTerritory->getId(); 
     $terrFailArr[] = $soqlObj2['records'][$i]['Name']; 
    } else { 
     $lastModifiedDate = new \DateTime(
      $soqlObj2['records'][$i]['LastModifiedDate'] 
     ); 

     if ($lastModifiedDate > $entTerritory->getUpdatedAt()) { 
      // obtained a territory, we update its data 
      $entTerritory->setName($soqlObj2['records'][0]['Name']); 
     } 

     $em->flush(); // ---> FLUSH HERE 

     $terrArr[] = $entTerritory->getId(); 
    } 
} 

for ($i = 0; $i < 6000; $i++) { 
    // SELECT HERE - need to find if Territory already exists 
    $entTerritory = $em->getRepository('PDOneBundle:Territory')->findOneBy(array('veeva_territory_id' => $soqlObj2['records'][$i]['Id'])); 

    if (!$entTerritory) { 
     // if there is no territory, then we add 
     $newTerritory = new Entity\Territory(); 

     // we set the values from veeva 
     if ($soqlObj2['records'][$i]['Id'] !== null || $soqlObj2['records'][$i]['Id'] !== "") { 
      $newTerritory->setVeevaTerritoryId($soqlObj2['records'][$i]['Id']); 
      $newTerritory->setName($soqlObj2['records'][$i]['Name']); 

      $em->persist($newTerritory); 
     } 

     $terrArr[] = $newTerritory->getId(); 
     $terrFailArr[] = $soqlObj2['records'][$i]['Name']; 
    } else { 
     $lastModifiedDate = new \DateTime(
      $soqlObj2['records'][$i]['LastModifiedDate'] 
     ); 

     if ($lastModifiedDate > $entTerritory->getUpdatedAt()) { 
      // obtained a territory, we update its data 
      $entTerritory->setName($soqlObj2['records'][0]['Name']); 
     } 

     $em->flush(); // ---> FLUSH HERE 

     $terrArr[] = $entTerritory->getId(); 
    } 
} 

$em->flush(); // ---> FLUSH FOR INSERT HERE 

for ($i = 0; $i < 6000; $i++) { 
    // SELECT HERE - need to find if Territory already exists 
    $entTerritory = $em->getRepository('PDOneBundle:Territory')->findOneBy(array('veeva_territory_id' => $soqlObj2['records'][$i]['Id'])); 

    if (!$entTerritory) { 
     // if there is no territory, then we add 
     $newTerritory = new Entity\Territory(); 

     // we set the values from veeva 
     if ($soqlObj2['records'][$i]['Id'] !== null || $soqlObj2['records'][$i]['Id'] !== "") { 
      $newTerritory->setVeevaTerritoryId($soqlObj2['records'][$i]['Id']); 
      $newTerritory->setName($soqlObj2['records'][$i]['Name']); 

      $em->persist($newTerritory); 
     } 

     $terrArr[] = $newTerritory->getId(); 
     $terrFailArr[] = $soqlObj2['records'][$i]['Name']; 
    } else { 
     $lastModifiedDate = new \DateTime(
      $soqlObj2['records'][$i]['LastModifiedDate'] 
     ); 

     if ($lastModifiedDate > $entTerritory->getUpdatedAt()) { 
      // obtained a territory, we update its data 
      $entTerritory->setName($soqlObj2['records'][0]['Name']); 
     } 

     $terrArr[] = $entTerritory->getId(); 
    } 
} 

$em->flush(); // ---> FLUSH FOR INSERT AND UPDATE HERE 

我還發現圍繞一個主題這here他們說:

當你有更新多個實體,從 檢索它們所有的數據庫,並遍歷ORM實體被稱爲壞 做法。

你不應該做這樣的:

$friend = $em->getReference('Octivi\Entity\User', $friendId); $users = 
$this->findAll(); 

foreach ($users as $user) { 
    $user->setFriend($friend); 
    $em->persist($user); } 

$em->flush(); 

相反,你應該依靠UPDATE查詢:

$qb->update('Octivi:User', 'u') 
    ->set('u.friend', $friendId) 
    ->getQuery()->execute(); 

多虧了這一點,我們只執行一個SQL UPDATE語句,而不是每個用戶實體的N更新。

那麼,最好的方法是什麼?爲什麼?

+1

您需要理論批處理。點擊此處:http://doctrine-orm.readthedocs.org/en/latest/reference/batch-processing.html – reverbnation

回答

3

在我看來,使用SQL是批處理的最佳/性能方式。已知學說佔用大量內存並可能很快達到允許的內存大小。