2017-07-14 46 views
3

我正在处理许多csv中的300000行的导入。学说插入许多数据

首先,我将csv导入数据库中的每一行。

我想解析所有行并将其插入到具有某种关系数据的右表中。

所以我已经试过这样:

$qb = $this->entityManager->createQueryBuilder(); 
    $flows = $qb->select('flow') 
     ->from('AppBundle:FlowAndata', 'flow') 
     ->getQuery() 
     ->getResult(); 

    $countRows = 0; 
    foreach ($flows as $row) { 
     //some check 
     $entity = new TestTable(); 
     $entity->setCode($row->getCode()); 
     //many other fields 
     $this->entityManager->persist($entity); 
     $this->entityManager->flush(); 
    } 

在这种情况下,所有的过程花了大约5秒钟的每一行!

现在如果我添加setMaxResults这样的:

$qb = $this->entityManager->createQueryBuilder(); 
    $flows = $qb->select('flow') 
     ->from('AppBundle:FlowAndata', 'flow') 
     ->setMaxResults(100) 
     ->getQuery() 
     ->getResult(); 

花了不到1秒!

所以我想获得的所有行,并将其与setMaxResult分成递归函数是这样的:

$qb = $this->entityManager->createQueryBuilder(); 
    $flows = $qb->select('flow') 
     ->from('AppBundle:FlowAndata', 'flow') 
     ->getQuery() 
     ->getResult(); 

    $countFlows = count($flows); 
    $numberOfQuery = $countFlows/100; 

    for ($i = 0; $i <= $numberOfQuery; $i++) { 
     $this->entityManager->clear(); 
     $qb = $this->entityManager->createQueryBuilder(); 
     $flows = $qb->select('flow') 
      ->from('AppBundle:FlowAndata', 'flow') 
      ->setFirstResult($i * 100) 
      ->setMaxResults(100) 
      ->getQuery() 
      ->getResult(); 

    } 

这样,我创造了许多查询分裂成100行。 是一种很好的做法,还是有更好的方法来解析许多行并插入它?

回答

4

official documentation of Doctrine推荐的有效方法是利用EntityManager的事务性写后行为。

迭代用于数据处理

较大的结果,您可以使用iterate()方法只遍历一个大的结果,并没有UPDATE或DELETE意向。从$query->iterate()返回的IterableResult实例实现了Iterator接口,因此您可以使用以下方法处理没有内存问题的较大结果。 (See example

批量插入

批量插入在学说是成批最好进行,服用EntityManager的事务后写行为的优势。 [...]您可能需要尝试批量大小以找到最适合您的尺寸。较大的批量意味着更多内部准备好的语句重用,但在flush期间意味着更多的工作。 (See example

版混合这两种技术(内部实体库):

$q = $this->_em->createQuery('SELECT f FROM AppBundle:FlowAndata f'); 
$iterableResult = $q->iterate(); 

$i = 0; 
$batchSize = 100; 

foreach ($iterableResult as $row) { 
    // do stuff with the data in the row, $row[0] is always the object 
    /** @var AppBundle\Entity\FlowAndata $flow */ 
    $flow = $row[0]; 

    //some check 
    $entity = new TestTable(); 
    $entity->setCode($row->getCode()); 
    //many other fields 

    $this->_em->persist($entity); 

    $i++; 
    if (($i % $batchSize) === 0) { 
     $this->_em->flush(); 
     // Detaches all objects from Doctrine! 
     $this->_em->clear(); 
    } else { 
     // detach from Doctrine, so that it can be Garbage-Collected immediately 
     $this->_em->detach($flow); 
    } 
} 

$this->_em->flush(); //Persist objects that did not make up an entire batch 
$this->_em->clear(); 
+1

大它的工作原理来得更快! 谢谢 –