Большой импорт Excel в DB очень медленный в Symfony

У меня есть сценарий, который импортирует большой файл Excel с большим количеством foreach es, и после 50-ти итераций он становится невыносимо медленным … Могу ли я как-то улучшить это?

Я стараюсь сделать это максимально читабельным:

 foreach worksheet (approx 20) { NEW DB ENTRY, PERSIST, FLUSH (account) foreach row (10-100){ NEW DB ENTRY, PERSIST, FLUSH (object) foreach column (approx. 10){ CREATE NEW DB ENTRY, FOREIGN KEY to 'object', PERSIST, FLUSH (weekdates) } foreach column (approx. 50){ CREATE NEW DB ENTRY, FOREIGN KEY to 'object', PERSIST, FLUSH (scheduleEntry) CREATE NEW DB ENTRY, FOREIGN KEY to 'scheduleEntry', PERSIST, FLUSH (scheduleObject) CREATE NEW DB ENTRY, FOREIGN KEY to 'scheduleObject', PERSIST, FLUSH (scheduleModule) /* WORST CASE IS THAT HERE WE HAVE FLUSHED 100000 times */ } } } 

Есть ли способ закрепить особенно последний foreach? Я думаю, мне нужно каждый раз промывать, поскольку я должен использовать FOREIGN KEY предыдущую запись для новой, я прав? По медленному я имею в виду, что для файла excel требуется 24 часа. У него были цифры в примере.

Фактический (все еще простой) код выглядит так:

 /* Create Excel */ $excel = $this->getContainer()->get('phpexcel')->createPHPExcelObject(Constants::FULL_PATH . 'excel/touren_' . $filename . '.xls'); $sheets = $excel->getAllSheets(); foreach ($sheets as $id => $sheet) { $ws = $sheet->toArray(); /* Read sth from first line and create an 'account' from this */ $n = new Network(); .... $em->persist($n); try { $em->flush(); $output->writeln('----><info>Inserted in DB</info>'); } catch (Exception $e) { $output->writeln('----><error>DB ERROR</error>'); } /* Go through all rows of current WorkSheet */ foreach ($ws as $row) { /* Create new Object */ $object = new Object(); ... $em->persist($object); try { $em->flush(); $output->writeln("------->Save Object to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save Object to DB: <error>Failed: " . $e->getMessage() . "</error>"); } /* Create new Tour for weekday/client */ $tour = new Tour(); $tour->setNetwork($n); /* More foreach */ foreach ($clientKey as $filialNo => $filialKey) { $tourObject = new TourObject(); $tourObject->setTour($tour); $tourObject->setObject($o); $em->persist($tourObject); /* Count Intervals */ foreach ($filialKey as $tasks) { if (!$tourObject->getModule()->contains($module)) { $tourObject->addModule($module); $em->persist($tourObject); /* More foreach */ foreach ($period as $date) { $schedule = new Schedule(); $schedule->setTour($tour); .... $em->persist($schedule); try { $em->flush(); $output->writeln("------->Save Schedule to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save Schedule to DB: <error>Failed: " . $e->getMessage() . "</error>"); } $scheduleObject = new ScheduleObject(); $scheduleObject->setSchedule($schedule); .... $em->persist($scheduleObject); try { $em->flush(); $output->writeln("------->Save ScheduleObject to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save ScheduleObject to DB: <error>Failed: " . $e->getMessage() . "</error>"); } $scheduleObjectModule = new ScheduleObjectModule(); $scheduleObjectModule->setScheduleObject($scheduleObject); $em->persist($scheduleObjectModule); try { $em->flush(); $output->writeln("------->Save ScheduleObjectModule to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save ScheduleObjectModule to DB: <error>Failed: " . $e->getMessage() . "</error>"); } } } } } /* Flush all?!? */ try { $em->flush(); $output->writeln("------->Save Task to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save Task to DB: <error>Failed: " . $e->getMessage() . "</error>"); } } 

Каждый объект, который вы создаете / сохраняете через EntityManager, хранится в UnitOfWork и теперь стал «управляемым» объектом. Если этот UnitOfWork заполняется, он довольно тяжелый для системы. Вы можете вызвать $ entityManager-> clear () после каждого «листа», чтобы UoW очистился после каждой итерации.

Каждый объект имеет свой собственный UnitOfWork, и вы можете очистить UoW для каждого объекта отдельно, но поскольку вы создаете множество объектов, я бы предложил не указывать класс сущности и просто очистить все из них.

  ... /* Flush all?!? */ try { $em->flush(); $em->clear(); $output->writeln("------->Save Task to DB: <info>OK</info>"); } catch (\Exception $e) { $output->writeln("------->Save Task to DB: <error>Failed: " . $e->getMessage() . "</error>"); } 

Или вы можете использовать собственные запросы для вставки в свою БД, но это может быть не всегда то, что вы хотите с точки зрения согласованности данных и т. Д.

Также, как указано выше, вам не нужно скрываться после каждого объекта. Если вы вызываете flush только один раз, после каждого «листа», Doctrine будет делать все инструкции вставки сразу.

Я считаю, что хорошим решением является использование собственной утилиты DB для этого (например, Mysql Load data infile )

Это будет намного быстрее, чем все, что вы можете написать на PHP.

  • Как загрузить файлы RAR, CSV, DOC, DOCX, XLS и XLSX в приложение Symfony2
  • SonataAdminBundle экспортирует html вместо xls
  • Проверка данных с помощью PHPExcel
  • Облицовка проблемы при попытке создания excel с раскрывающимися списками списков на одном листе
  • Не удалось импортировать .xls - Symfony PHP
  • Давайте будем гением компьютера.