Symfony和Doctrine中的批量插入:如何选择批量大小?

时间:2016-07-07 09:18:08

标签: symfony doctrine-orm

我正在使用 Symfony 2.7 Doctrine 开发网络应用。 Symfony命令用于执行大量实体的更新。

我关注Doctrine guidelines并且不使用$entityManager->flush()每个实体。

这是Doctrine示例代码:

<?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->flush(); //Persist objects that did not make up an entire batch

准则说:

  

您可能需要尝试使用批量大小来查找其大小   最适合你。较大的批量大小意味着更准备的声明   在内部重复使用,但也意味着更多的工作在冲洗期间。

所以我尝试了不同的批量大小。批处理大小越大,命令完成其任务的速度就越快。

因此问题是:大批量的缺点是什么?在所有实体更新后,为什么不再使用$entityManager->flush()

文件说,更大的批量大小&#34;意味着在冲洗期间更多的工作&#34;。但是为什么/何时这可能是一个问题?

我可以看到的唯一缺点是更新期间Exceptions:如果脚本在保存的已更改位置之前停止,则更改将丢失。这是唯一的限制吗?

4 个答案:

答案 0 :(得分:10)

  

大批量的缺点是什么?

如果为示例创建10,000个实体,则大批量可以使用大量内存。如果不以批处理方式保存实体,它们将在内存中累积,如果程序达到内存限制,则可能会导致整个脚本崩溃。

  

为什么不在所有实体更新后仅使用$entityManager->flush()

这是可能的,但是在调用flush()一次之前将10,000个实体存储在内存中将比使用100保存实体100使用更多内存。它可能还需要更多时间。

  

该文件只是说,较大的批量大小“意味着更多的工作时间”。但是为什么/何时这可能是一个问题?

如果您对最大批量大小没有任何性能问题,可能是因为您的数据不足以填满内存或破坏PHP的内存管理。

因此批量的大小取决于多个因素,主要是内存使用量与时间的关系。如果脚本占用太多RAM,则必须降低批处理的大小。但是使用非常小的批次可能比更大的批次花费更多的时间。因此,您必须运行多个测试才能调整此大小,以便它使用大部分可用内存但不会更多。

我没有任何证据,但我记得曾与数千家实体合作过。当我只使用一个flush()时,我看到进度条变慢了,看起来我的程序越来越慢,因为我在内存中添加了越来越多的实体。

答案 1 :(得分:4)

如果刷新花费太多时间,则可能超过服务器的最长执行时间,并失去连接。

答案 2 :(得分:1)

根据我的经验,每批100个实体效果很好。取决于实体,200太多而其他实体,我可以做1000.

要正确批量插入,您需要以下命令:

$em->clear();
每次冲洗后

。原因是Doctrine没有将它冲刷到DB中的对象释放出来。这意味着如果你不“清除”它们,内存消耗将继续增加,直到你破坏你的PHP内存限制并使你的操作崩溃。

我还建议不要将PHP内存限制增加到更高的值。如果这样做,您可能会在服务器上造成巨大的延迟,这可能会增加与服务器的连接数,然后使其崩溃。

还建议在Web Server上载表单页面之外处理批处理操作。因此,将数据保存在Blob中,然后使用Cronjob任务处理它,该任务将在所需的时间(Web服务器的峰值使用时间之外)处理批处理。

答案 3 :(得分:0)

正如Doctrine文档中所建议的那样,ORM不是批处理使用的最佳工具。

除非您的实体需要某些特定逻辑(如侦听器),否则请避免使用ORM并直接使用DBAL。