2017-07-14 56 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

大它的工作原理來得更快! 謝謝 –