学说2 - 一次注射多次插入

2022-08-30 14:18:12

我是教义的新手,对我来说仍然有一些模糊的领域。在本例中,我使用循环和实体管理器在数据库中插入新记录。它工作正常,但我注意到教义按实体进行一个插入查询,这可能会变得非常大。

使用 Doctrine2 和 Symfony 2.3,我想知道我们如何设置它,以便它只进行 1 个包含所有值的插入查询(当然,我们只谈论 1 个实体)。

我的意思是改变这个:

INSERT INTO dummy_table VALUES (x1, y1)    
INSERT INTO dummy_table VALUES (x2, y2)

INSERT INTO dummy_table VALUES (x1, y1), (x2, y2)

这是我的代码:

$em = $this->container->get('doctrine')->getManager();

foreach($items as $item){
    $newItem = new Product($item['datas']);
    $em->persist($newItem);
}

$em->flush();

答案 1

根据这个答案,Doctrine2 不允许您将多个 INSERT 语句合并为一个:

有些人似乎想知道为什么教义不使用多插入(插入到(...)值(...),(...),(...),(...),...

首先,这种语法仅在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

你可以试试这个分叉 https://github.com/stas29a/doctrine2。它完全实现了您想要的。我在MySQL中测试了它,它工作正常,比批处理快5倍。这个分叉获取第一个插入的id,并在php中递增它以获取其他id。它适用于大多数情况,但并非在所有情况下都有效。因此,您需要了解使用此分叉时您正在做什么。


推荐