【问题标题】:Most efficient way to do batch INSERT IGNORE using doctrine 2使用学说 2 进行批量 INSERT IGNORE 的最有效方法
【发布时间】:2014-02-05 22:27:23
【问题描述】:

我有一个脚本需要获取数据库中的条目列表,然后迭代那些在另一个表中创建新条目(如果它们不存在)。

目前正在做:

foreach($entries as $entry){
    $newItem = new Item();
    $newItem->setAttribute($entry->getAttribute());
    $entityManager->persist($newItem);
    try{
        $entityManager->flush();
    } catch(\Exception $e){
        if(!strpos($e->getMessage(),'Duplicate')){
            throw $e;
        }
        $entityManager = $this->getDoctrine()->getManager(); 
        //refreshes the entity manager
    }

}

但是这样做非常耗时,有 1000 个条目,脚本有时需要 10 分钟以上才能完成。我已经看到其他帖子建议在进行这样的批处理以每 20 条左右刷新一次记录时,问题是如果这 20 条中的一条是重复的,那么整个事务就会终止,我不确定我将如何回去尝试找到违规条目以将其排除,然后再次重新提交。

对此的任何帮助将不胜感激。

【问题讨论】:

  • 不要在flush() 你的批次在foreach() 循环内...

标签: php mysql symfony doctrine-orm


【解决方案1】:

您可以使用SELECT 来获取数据库中已经存在的记录,然后跳过这些记录。此外,尝试只执行一次flush()clear(),或者尝试使用批量大小。我还建议使用事务(如果您使用 InnoDB)。

$this->_em->getConnection()
    ->beginTransaction();

try {
    $created = array(/* all primary keys that already exist */);
    $i = 1;
    $batchSize = sizeof($entries);
    foreach ($entries as $entry) {

        if (in_array($entry->getMyPrimaryKey(), $created)) {
            continue;
        }

        $newItem = new Item();
        $newItem->setAttribute($entry->getAttribute());
        $entityManager->persist($newItem);

        if (($i % $batchSize) == 0) {
            $this->_em->flush();
            $this->_em->clear();
        }

        $i++;
    }

    $this->_em->getConnection()
        ->commit();
} catch (\Exception $e) {
    $this->_em->getConnection()
        ->rollback();
    $this->_em->close();

    throw new \RuntimeException($e->getMessage());
} 

【讨论】:

  • 另外,为什么我们在 foreach 循环中使用 $i,你们只是要运行刷新并在完成后清除?为什么不把它移到 foreach 之后呢?
  • 对不起,我更新了代码,想法是只调用一次flush(它对我有用),否则你将不得不考虑批量大小。虽然,如果您必须插入 32,000DBAL 可能是可行的解决方案。
  • @b.b3rn4rd 完全同意使用DBAL。有了这么多记录,任何类型的 ORM 都会崩溃:-/
  • @Chausser DBAL 基本上是 PDO 的包装器。因此,您将能够以最小的 Doctrine 开销插入数据。在这里阅读更多:docs.doctrine-project.org/projects/doctrine-dbal/en/latest/…
  • 警告 - 如果现有 PK 的数量很大(在我的情况下为 100k),这种方法将非常难看。
猜你喜欢
  • 2016-10-12
  • 2013-12-13
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 2015-05-05
相关资源
最近更新 更多