Symfony: Doctrine data fixture: como lidar com o arquivo csv grande?

Estou tentando inserir dados (em um database mySQL) de um arquivo “grande” CSV (3Mo / 37000 linhas / 7 colunas) usando dispositivos de dados de doctrine.

O processo é muito lento e, neste momento, não consegui ser bem sucedido (talvez eu tenha que aguardar um pouco mais).

Suponho que os dispositivos de dados da doctrine não se destinam a gerenciar essa quantidade de dados? Talvez a solução deve ser importar diretamente o meu csv para o database?

Alguma idéia de como proceder?

Aqui está o código:

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; } } 

Duas regras a seguir quando você cria grandes importações de lote como esta:

  • Desativar o log de SQL: ( $manager->getConnection()->getConfiguration()->setSQLLogger(null); ) para evitar uma enorme perda de memory.

  • Lave e limpe com freqüência em vez de apenas uma vez no final. Sugiro que você adicione if ($i % 25 == 0) { $manager->flush(); $manager->clear() } if ($i % 25 == 0) { $manager->flush(); $manager->clear() } dentro de seu loop, para eliminar cada 25 INSERTs.

EDITAR: uma última coisa que esqueci: não mantenha suas entidades dentro de variables ​​quando você não precisa mais delas. Aqui, no seu loop, você só precisa da entidade atual que está sendo processada, portanto, não armazene a entidade anterior em uma matriz de $coordinatesfrcity frenagem. Isso pode levá-lo a um estouro de memory se você continuar fazendo isso.

Há um ótimo exemplo no Docs: http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html

Use uma expressão de módulo (x% y) para implementar o processamento em lote, este exemplo irá inserir 20 por vez. Você pode otimizar isso dependendo do seu servidor.

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

Para dispositivos elétricos que precisam de muita memory, mas não dependem um do outro, eu lanço esse problema usando o sinalizador de anexos para inserir uma entidade (ou grupo menor de entidades) de cada vez:

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

Então eu escrevo um script Bash que executa esse comando quantas vezes eu preciso.

No seu caso, você poderia estender o comando Fixtures e ter uma bandeira que faça lotes de entidades – as primeiras 1000 linhas, então o 2º 1000, etc.