2017-07-14 1 views
3

私は多くのcsvの中で300000行のインポートに取り組んでいます。Doctrineは多くのデータを挿入します

まず、私は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と再帰関数に分割している:私は100行に分割さ多くのクエリを作成するには、このようにして

$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(); 

    } 

。 良い練習ですか、それとも多くの行を解析してItを挿入する方がいいですか?

答えて

4

official documentation of Doctrineで推奨されている効率的な方法では、取引の後書きの動作はEntityManagerです。あなたが大きな結果と無UPDATEまたはDELETE意思を反復処理するだけiterate()メソッドを使用することができるデータ処理

のための大規模な結果を反復

$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

グレートそれはより速く動作します! ありがとう –

関連する問題