Optimization Symfony2,条令,添加\插入\更新针对大量查询的最佳解决方案

Optimization Symfony2,条令,添加\插入\更新针对大量查询的最佳解决方案,optimization,symfony,doctrine-orm,Optimization,Symfony,Doctrine Orm,让我们假设我们有以下代码: while (true) { foreach($array as $row) { $item = $em->getRepository('reponame')->findOneBy(array('filter')); if (!$item) { $needPersist = true; $item = new Item(); }

让我们假设我们有以下代码:

while (true)
{
    foreach($array as $row)
    {
       $item = $em->getRepository('reponame')->findOneBy(array('filter'));

       if (!$item)
       {
           $needPersist = true;
           $item = new Item();
       }

       $item->setItemName()
       // and so on ...

       if ($needPersist)
       {
           $em->persist();
       }
    }
    $em->flush();
}
所以,关键是代码将被执行很多次(而服务器不会死掉:)。我们想优化它。每次我们:

  • 从存储库中选择“已存在”条目
  • 如果条目不存在,请创建它
  • 为其设置新(更新)变量
  • 应用操作(刷新)
  • 所以问题是-如何避免不必要的查询和优化“检查条目是否存在”?因为当有100-500个查询时,就不会那么可怕了。。。但当一次循环达到1000-10000时,这就太多了


    PS:DB中的每个条目都有几个列(不仅仅是ID)是唯一的。

    无论更新后是否需要它们保持不变,从数据库中检索10k+及以上条目并将其水合为php对象都需要太多内存。在这种情况下,您最好回退到并触发纯SQL查询

  • 不要逐个获取结果,而是用一个查询加载所有结果 例如。 假设您的筛选器要加载ID 1、2、10。所以QB应该是这样的:

    $allResults = ...
        ->where("o.id IN (:ids)")->setParameter("ids", $ids) 
        ->getQuery()
        ->getResults() ;
    
  • “对于每一个”这些结果,都要进行更新和刷新

  • 在执行该循环时,将获取的对象的ID保存在新数组中

  • 使用array_diff将该数组与原始数组进行比较。现在您有了第一次未获取的ID

  • 冲洗并重复:)

  • 不要忘记$em->clear()来释放内存


  • 虽然在处理10000条记录(不知道,从未测试过)时这仍然很慢,但是有两个大的查询要比10000个小的查询快得多。

    您的代码缺少一些细节-如果不仅仅是id,哪些数据标识条目?新条目的数据来自哪里?-,有一些错误(?)-
    findOneBy(数组('filter'))
    $item->setItemName()
    -为什么
    while(true))
    ?您的查询似乎只保留新项目。一些现有项目是否也需要更新?如果条目不仅仅由id标识,那么主键由哪些列组成。这听起来很像任何优化的起点。虽然(正确)-为了表明它可以从100万循环到100万循环(这是一般的例子),数据来自函数中的大量数据。是的,但点并没有错误,我在调用此代码之前检查它。表有4-5列(我不认为有多少列)。是,代码为“更新现有,如果不添加新”。现在主要是id+action(string),但我反对它,因为Symfony提倡面向对象的方法,使用dbal和数组至少在我看来是错误的。Imo更好的解决方案是延迟这些任务,并使用JobQueue/worker或类似的方法将它们与实际请求分离。通过这种方式,您可以保留(希望经过测试的)模型/实体、验证、DI等的所有symfony优点,而不必诉诸粗糙的黑客。请考虑一下可怜的灵魂,他们可能需要筛选您的“优化”脚本以查找bug或更改某些sql;)我在我的实际项目中这样做。所有这些都在symfony框架中(作为控制台命令),但使用dbal。尽管cli可以无限时间运行,但有数百万个数据库条目,orm/odm会占用您所有的内存并卡住。这是在一台有GB内存的机器上实现的。