2017-07-14 6 views
3

Ich arbeite an einem Import von 300000 Reihe in vielen CSV.Lehre einfügen viele Daten

Zuerst nehme ich CSV und importiere jede Zeile in eine Tabelle innerhalb meiner Datenbank.

Nachdem ich alle Zeile analysieren und einfügen in die richtige Tabelle mit einer Beziehung, dass Daten.

Ich habe dies so versucht:

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

In diesem Fall werden alle Verfahren dauerte etwa 5 Sekunden für jede Zeile!

Jetzt Wenn ich hinzufügen setMaxResults wie folgt aus:

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

Es dauerte weniger als 1 Sekunde!

Also habe ich gedacht, alle Zeilen zu erhalten und teilen Sie es in eine rekursive Funktion mit setMaxResult wie folgt aus:

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

    } 

Auf diese Weise habe ich viele Abfrage erstellen in 100 Zeilen aufgeteilt. Ist eine gute Übung oder gibt es eine bessere Möglichkeit, viele Zeilen zu analysieren und eine Einfügung von It machen?

Antwort

4

Der effiziente Weg, der von official documentation of Doctrine empfohlen wird, nutzt das transaktionale Write-Behind-Verhalten eines EntityManager.

Iterieren Große Ergebnisse für Datenverarbeitung

können Sie die iterate() Methode verwenden, nur ein großes Ergebnis iterieren und keine UPDATE oder DELETE Absicht. Die IterableResult -Instanz, die von $query->iterate() zurückgegeben wird, implementiert die Iterator-Schnittstelle, sodass Sie ein großes Ergebnis ohne Speicherprobleme mithilfe des folgenden Ansatzes verarbeiten können. (See example)

Bulk-Einsätze

Bulk-Einsätze in Lehre am besten in Chargen durchgeführt, unter Ausnutzung der Transaktionsschreib hinter Verhalten eines EntityManager nehmen. [...] Möglicherweise müssen Sie mit der Stapelgröße experimentieren, um die Größe zu finden, die für Sie am besten geeignet ist. Größere Chargengrößen bedeuten mehr interne Wiederverwendung von Anweisungen, bedeuten aber auch mehr Arbeit während flush. (See example)

Version beide Techniken Misch (Innen Entity Repository):

$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

Groß Es funktioniert mehr schneller! Danke –

Verwandte Themen