Doctrine2性能:插入/更新多行

时间:2015-06-18 03:13:51

标签: php mysql performance symfony doctrine-orm

假设我有6000个值,并且我正在对它们执行for循环,并使用Symfony2 + Doctrine执行INSERTUPDATE个动作,这是最佳/正确的方式执行这些陈述并保持良好的业绩水平?

第一

   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 个答案:

答案 0 :(得分:3)

在我看来,使用SQL是批处理的最佳/性能方式。众所周知,Doctrine会占用大量内存,并可能很快达到允许的内存大小。