douxiuyi6529 2015-06-18 03:13
浏览 45
已采纳

Doctrine2性能:插入/更新多行

Suppose that I have 6000 values and I am performing a for loop for cycle on them and perform INSERT or UPDATE actions using Symfony2 + Doctrine, which is the best/right way for execute those statements and keep good levels of performance?

First

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

Second

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

Third

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

I have also found a topic around this here and they says:

When you have to update multiple entities, retrieving them all from the database and iterating over ORM entities is known as a bad practice.

You should never do like:

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

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

$em->flush(); 

Instead, you should rely on the UPDATE query:

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

Thanks to it, we only execute one SQL UPDATE statement instead of N-updates for each User entity.

So, what is the best way and why?

  • 写回答

1条回答 默认 最新

  • du0204 2015-06-18 08:24
    关注

    In my opinion, using SQL is the best/performance way for batch process. Doctrine is known to take a lot of memory and might quickly reach the allowed memory size.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行