2017-05-03 2 views
1

Ich habe einen symfony-Befehl erstellt, der 2M-Einträge importieren und in die Datenbank einfügen soll.Symfony3/Doctrine 2 flush error

Ich lege einen Flush/Clear und gebe alle 500 Einträge, um es mit Doktrin einfügen und den Fortschritt der Insertion verfolgen zu können. Auf meinem Rechner mit einem Server mySQL Datenbank es funktioniert, aber auf dem entfernten Server mit Postgresql funktioniert es nicht, bekomme ich eine Nachricht:

[Symfony\Component\Debug\Exception\ContextErrorException] 
    Notice: Undefined index: 0000000025969b1e00000000029e7855 

Exception trace: 
() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:2917 
Doctrine\ORM\UnitOfWork->getEntityIdentifier() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:656 
Doctrine\ORM\Persisters\Entity\BasicEntityPersister->prepareUpdateData() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:692 
Doctrine\ORM\Persisters\Entity\BasicEntityPersister->prepareInsertData() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:271 
Doctrine\ORM\Persisters\Entity\BasicEntityPersister->executeInserts() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:1014 
Doctrine\ORM\UnitOfWork->executeInserts() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:378 
Doctrine\ORM\UnitOfWork->commit() at /var/nginx/kweeri-next/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:356 
Doctrine\ORM\EntityManager->flush() at /var/nginx/kweeri-next/var/cache/dev/appDevDebugProjectContainer.php:6083 
DoctrineORMEntityManager_00000000612352fa000000006464aa610448bf5c446411a05ad87329e18cead6->flush() at /var/nginx/kweeri-next/src/AppBundle/Utility/Clients/IRI/PPS/ImportItems.php:219 

Dies ist der Code, wo der Flush eine Mitteilung stellt.

public function importDictionnary($companyMachineName, $file) { 
     $company = $this->em->getRepository("AGAdminBundle:Company")->findOneBy(["machineName" => $companyMachineName]); 
     if (!$company) { 
      throw new EntityNotFoundException("no company found for $companyMachineName"); 
     } 
     $eans = $file; 
     $this->logger->addInfo("File downloaded"); 

     $product_repo = $this->em->getRepository(\AppBundle\Entity\PPS\Product::class); 
     $existings = array_map(function (\AppBundle\Entity\PPS\Product $product) { 
      return $product->getEan(); 
     }, $product_repo->findBy(["company" => $company])); 
     $old_value = -1; 
     foreach ($eans as $k => $ean) { 
      if (!in_array($ean, $existings)) { 
       $this->em->persist(new \AppBundle\Entity\PPS\Product($ean, $company)); 

       if ($k % 500 == 0) { 
        yield round(($k/count($eans)) * 100); 
        $this->em->flush(); 
        $this->em->clear(); 
       } 
      } 
     } 
     $this->em->flush(); 
    } 

EDIT: es arround 30 Sekunden dauert 2 auf meinem Rechner zu erhalten. Auf der entfernten Maschine dauert es bis zu 20 Minuten, bevor sie 2 ergibt und stoppt.

+1

Nicht so vertraut mit der Ausbeute, wie ich sein sollte. Wird $ company nach jeweils 500 Loops neu geladen? Wenn nicht, dann sollte die mysql-Version natürlich ebenfalls fehlschlagen. – Cerad

+0

@Cerad Ich habe dieses Problem behoben, indem ich die CompanyId beibehalten und dann nur die Referenz neu laden konnte, wie in einer Antwort vorgeschlagen. aber immer noch sehr langsam: 2 Stunden auf mySQL, 11 Stunden auf PostgreSQL. – d3cima

+0

Es gibt einige hundert Fragen zur Beschleunigung von Importen. Aber keine magische Kugel. Die Verwendung des ORM fügt einen nicht-trivialen Overhead hinzu. Wenn man auf DBAL herunterfährt, hilft das sehr, aber 1,5 Millionen von allem zu tun, wird langsam sein, egal was passiert. – Cerad

Antwort

2

Wenn Sie $em->clear() anrufen, wird die gesamte Identitätskarte gelöscht. Sie müssen alle Objekte aus der Datenbank neu laden, um mit ihnen arbeiten zu können. Andernfalls könnte doctrine das Objekt in der Identitätskarte nicht finden, was zu undefinierten Indexfehlern führt.

Falls Sie die Objekt-ID kennen und Sie nicht mit Objekteigenschaften arbeiten müssen, können Sie eine Referenz verwenden, anstatt das Objekt aus der Datenbank zu laden.

+0

Ich versuchte es mit einer Referenz meiner Firma und es funktioniert, aber es ist langsam wie die Hölle. 1500000 auf mySQL für 2h und 11h für Postgresql. – d3cima

+0

Können Sie SQL-Abfragen überwachen? Ich schätze, Sie machen eine SELECT innerhalb einer Schleife (Sie können es versehentlich durch Lazy Load tun). – kormik