2016-03-04 8 views
6

Ich versuche, (in einer mySQL-Datenbank) Daten aus einer "großen" CSV-Datei (3Mo/37000 Zeilen/7 Spalten) unter Verwendung von Doktrin Daten Fixtures einzufügen.Symfony: Doctrine data fixture: Wie geht man mit einer großen CSV-Datei um?

Der Prozess ist sehr langsam und zu dieser Zeit konnte ich nicht erfolgreich sein (vielleicht musste ich ein bisschen mehr warten).

Ich nehme an, dass Doktrin Daten Fixtures nicht so viele Daten verwalten sollen? Vielleicht sollte die Lösung sein, meinen CSV direkt in die Datenbank zu importieren?

Irgendeine Idee, wie Sie vorgehen? Hier

ist der Code:

<?php 

namespace FBN\GuideBundle\DataFixtures\ORM; 

use Doctrine\Common\DataFixtures\AbstractFixture; 
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; 
use Doctrine\Common\Persistence\ObjectManager; 
use FBN\GuideBundle\Entity\CoordinatesFRCity as CoordFRCity; 

class CoordinatesFRCity extends AbstractFixture implements OrderedFixtureInterface 
{ 
    public function load(ObjectManager $manager) 
    { 
     $csv = fopen(dirname(__FILE__).'/Resources/Coordinates/CoordinatesFRCity.csv', 'r'); 

     $i = 0; 

     while (!feof($csv)) { 
      $line = fgetcsv($csv); 

      $coordinatesfrcity[$i] = new CoordFRCity(); 
      $coordinatesfrcity[$i]->setAreaPre2016($line[0]); 
      $coordinatesfrcity[$i]->setAreaPost2016($line[1]); 
      $coordinatesfrcity[$i]->setDeptNum($line[2]); 
      $coordinatesfrcity[$i]->setDeptName($line[3]); 
      $coordinatesfrcity[$i]->setdistrict($line[4]); 
      $coordinatesfrcity[$i]->setpostCode($line[5]); 
      $coordinatesfrcity[$i]->setCity($line[6]); 

      $manager->persist($coordinatesfrcity[$i]); 

      $this->addReference('coordinatesfrcity-'.$i, $coordinatesfrcity[$i]); 


      $i = $i + 1; 
     } 

     fclose($csv); 

     $manager->flush(); 
    } 

    public function getOrder() 
    { 
     return 1; 
    } 
} 

Antwort

6

Zwei Regeln zu folgen, wenn Sie große Batch-Importe wie folgt zu erstellen:

  • Disable SQL Logging: ($manager->getConnection()->getConfiguration()->setSQLLogger(null);) großen Speicherverlust zu vermeiden.

  • Spülen und löschen Sie häufig und nicht nur einmal am Ende. Ich schlage vor, Sie fügen if ($i % 25 == 0) { $manager->flush(); $manager->clear() } innerhalb Ihrer Schleife hinzu, um alle 25 INSERTs zu spülen.

EDIT: Eine letzte Sache, die ich vergessen: nicht halten Ihre Entitäten innerhalb Variablen, wenn Sie sie nicht mehr benötigen. Hier benötigen Sie in Ihrer Schleife nur die aktuelle Entität, die gerade verarbeitet wird, also speichern Sie die vorherige Entität nicht in einem $coordinatesfrcity Array. Dies könnte zu einem Speicherüberlauf führen, wenn Sie dies weiterhin tun.

+0

Dank. Ich hatte versucht, bei jedem Einsatz zu spülen, aber es war eine zu wichtige Frequenz, nehme ich an. Ich werde deinen Vorschlag versuchen. Entschuldigung aber was ist SQL Logging? – Cruz

+0

Doctrine verfügt über ein Protokollierungssystem, das die Spuren der ausgeführten SQL-Abfragen enthält. In diesem Zusammenhang werden Sie es nicht brauchen, und es wird eine nutzlose Speicherkosten sein. – Terenoth

+0

Ok Ich verstehe, was SQL-Protokollierung ist. Und du hast Recht, dieser Tisch stammt aus einem anderen Code und ist hier nicht notwendig. – Cruz

0

Es ist ein großartiges Beispiel in dem Text & Tabellen: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html

Verwenden Sie einen Modulo (x% y) Ausdruck Stapelverarbeitung zu implementieren, dieses Beispiel Einsatz 20 auf einmal. Möglicherweise können Sie dies abhängig von Ihrem Server optimieren.

$batchSize = 20; 
for ($i = 1; $i <= 10000; ++$i) { 
    $user = new CmsUser; 
    $user->setStatus('user'); 
    $user->setUsername('user' . $i); 
    $user->setName('Mr.Smith-' . $i); 
    $em->persist($user); 
    if (($i % $batchSize) === 0) { 
     $em->flush(); 
     $em->clear(); // Detaches all objects from Doctrine! 
    } 
} 
$em->flush(); //Persist objects that did not make up an entire batch 
$em->clear(); 
+0

Danke. Dies ist die gleiche Antwort wie Sogara. Ich werde es so schnell wie möglich versuchen. – Cruz

+0

War letztens auf der Dokumentseite selbst mit einem ähnlichen Problem, dachte nur, ich würde dir eine Quelle geben, so wie ich sie zur Hand hatte. – Sarcoma

+0

Vielen Dank dafür! – Cruz

0

für die Lampen, die viel Speicher benötigen, aber nicht abhängig von einander, ich dieses Problem umgehen, indem Sie die Ergänzungsflag mit einer Einheit (oder kleinere Gruppe von Einheiten) zu einem Zeitpunkt einzufügen:

bin/console doctrine:fixtures:load --fixtures="memory_hungry_fixture.file" --append 

Dann schreibe ich ein Bash-Skript, das diesen Befehl so oft wie ich brauche.

In Ihrem Fall könnten Sie die Fixtures Befehl erweitern und eine Flagge haben die Chargen von Entitäten tut - die ersten 1000 Zeilen, dann die 2. 1000 usw.

Verwandte Themen