2014-02-05 21 views
6

我有一个需要的脚本获取数据库中的条目列表,然后遍历那些在另一个表中创建新条目的脚本,如果它们不存在的话。使用原则2执行批量INSERT IGNORE的最有效方法

目前即时通讯做:

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是重复的,那么整个交易死亡,林不知道我将如何回去尝试和找到有问题的条目以在再次提交之前将其排除。

任何帮助,这将不胜感激。

+0

不要'的flush()'你批'里面的foreach()'循环... –

回答

4

你可以做一个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()); 
} 
+0

在所有交易1做他们的问题是,如果我有32,000个条目的交易是巨大的,超过脚本的最长运行时间。它也占用了所有的系统资源,这就是为什么我使用更频繁的冲刷的原因 – Chausser

+1

另外为什么我们在foreach循环中的所有人都只是在执行flush操作时清除并清除它?为什么不把它放在foreach之后? – Chausser

+1

对不起,我更新了代码,想法是只调用一次“flush”(它对我有用),否则你将不得不玩大约一批。虽然,如果你必须插入'32,000','DBAL'可能是可行的解决方案。 –

相关问题