【问题标题】:Doctrine combine JoinTable inserts教义结合 JoinTable 插入
【发布时间】:2023-04-06 15:07:01
【问题描述】:

我有两个实体:

Voucher
Support

这些实体有一个名为

的连接表
 voucher_support

当我将 1000 个现有支持添加到新凭证时,它将在凭证_support 处向我的 SQL 服务器调用 1000 个 INSERT 查询。肯定有 50.000 也有 50.000 插入。

我怎样才能实现这一原则,只需进行一次 INSERT 并提高我的性能?

编辑

我认为批量插入不是解决方案。 这是我当前的代码以便更好地理解:

$voucher = new Voucher();
$voucher->setCreatedAt(new \DateTime());
$supports = $this->em->getRepository('Support')->getOpen();
foreach($supports as $support){
    // this generates for each support a INSERT in join table.
    $voucher->addSupport($support);
}
$this->em->persist($voucher);
$this->em->flush();

【问题讨论】:

    标签: php symfony doctrine-orm doctrine


    【解决方案1】:

    Doctrine2 不允许您将多个 INSERT 语句合并为一个:

    有些人似乎想知道为什么 Doctrine 不使用多重插入(insert into (...) values (...), (...), (...), ...

    首先,这种语法只在 mysql 和更新的 postgresql 版本上被支持。其次,当使用 AUTO_INCREMENT 或 SERIAL 时,没有简单的方法可以在这样的多插入中获取所有生成的标识符,并且 ORM 需要标识符来进行对象的身份管理。最后,插入性能很少是 ORM 的瓶颈。普通插入对于大多数情况来说已经足够快了,如果你真的想做快速批量插入,那么多插入无论如何都不是最好的方法,即 Postgres COPY 或 Mysql LOAD DATA INFILE 快几个数量级。

    这就是为什么不值得努力在 ORM 中实现对 mysql 和 postgresql 执行多插入的抽象的原因。 您可以在此处阅读有关 Doctrine2 批处理的更多信息:http://www.doctrine-project.org/blog/doctrine2-batch-processing.html

    您可以切换到 DBAL 或通过在一定数量的插入后刷新实体管理器来小批量处理数据:

    $batchSize = 20;
    
    foreach ($items as $i => $item) {
         $product = new Product($item['datas']);
    
         $em->persist($product);
    
         // flush everything to the database every 20 inserts
         if (($i % $batchSize) == 0) {
             $em->flush();
             $em->clear();
        }
    }
    
    // flush the remaining objects
    $em->flush();
    $em->clear();
    

    【讨论】:

    【解决方案2】:

    阅读 Bulk inserts 部分 Doctrine2 文档。它建议对每个“批次”使用flush()。 您还应该考虑用事务包装它。

    <?php
    $batchSize = 20;
    for ($i = 1; $i <= 10000; ++$i) {
        $user = new CmsUser;
        $user->setStatus('user');
        $user->setUsername('user' . $i);
        $user->setName('Mr.Smith-' . $i);
        $em->persist($user);
        if (($i % $batchSize) === 0) {
            $em->flush();
            $em->clear(); // Detaches all objects from Doctrine!
        }
    }
    $em->flush(); //Persist objects that did not make up an entire batch
    $em->clear();
    

    【讨论】:

    • 我知道这种方法并且已经在其他部分使用它。但我不插入多个凭证或支持。连接表插入是问题所在。
    • 您可以使用带有INSERT INTO ... SELECT FROM ... 的本机查询将行填充到连接表中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 2012-05-09
    • 2020-08-14
    • 2015-02-25
    • 2018-07-23
    • 1970-01-01
    相关资源
    最近更新 更多