【发布时间】:2019-09-25 07:38:50
【问题描述】:
我需要使用 Symfony 从 myqsl 数据库中的 csv 文件 (45 Mo) 导入大量数据。我导入了 League\Csv\Reader 库 我用教义发出命令。 它有效,但我很慢。 我怎样才能加快这个速度?
我试过了:
在 $this->em->flush() 之后添加:$this->em->clear();
adding : //禁用 SQL 日志记录:以避免大量内存丢失。
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
。
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use App\Entity\Developer;
use App\Entity\BadgeLabel;
use Doctrine\ORM\EntityManagerInterface;
use League\Csv\Reader;
class CsvImportCommand extends Command
{
public function __construct(EntityManagerInterface $em){
parent::__construct();
$this->em = $em;
}
// the name of the command (the part after "bin/console")
protected static $defaultName = 'app:import-developpers';
protected function configure()
{
$this
// the short description shown while running "php bin/console list"
->setDescription('Import a new developper.')
// the full command description shown when running the command with
// the "--help" option
->setHelp('This command allows you to import a develpper...')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Importation en cours');
$reader = Reader::createFromPath('%kernel.root_dir%/../src/Data/developers_big.csv')
->setHeaderOffset(0)
;
$results = $reader->getrecords();
$io->progressStart(iterator_count($results));
//Disable SQL Logging: to avoid huge memory loss.
$this->em->getConnection()->getConfiguration()->setSQLLogger(null);
foreach ($results as $row) {
$developer = $this->em->getRepository(Developer::class)
->findOneBy([
'firstName' => ($row['FIRSTNAME']),
'lastName'=> ($row['LASTNAME'])
])
;
if (null === $developer) {
$developer = new developer;
$developer
->setFirstName($row['FIRSTNAME'])
->setLastName($row['LASTNAME']);
$this->em->persist($developer);
$this->em->flush();
$this->em->clear();
}
$badgeLabel = $this->em->getRepository(BadgeLabel::class)
->findOneBy([
'name' => ($row['BADGE LABEL']),
'level'=> ($row['BADGE LEVEL'])
])
;
if (null === $badgeLabel) {
$badgeLabel = new BadgeLabel;
$badgeLabel
->setName($row['BADGE LABEL'])
->setLevel($row['BADGE LEVEL']);
$this->em->persist($badgeLabel);
$this->em->flush();
$this->em->clear();
}
$developer
->addBadgeLabel($badgeLabel);
$io->progressAdvance();
}
$this->em->flush();
$this->em->clear();
$io->progressFinish();
$io->success('Importation terminée avec succès');
}
}
该命令运行缓慢。 15 分钟后,只有 32% 的数据上传到我的 Mysql 数据库中。我预计最多 2 分钟
【问题讨论】:
-
您应该避免循环中的两个“findOneBy”。尝试在 foreach 之外获取所有开发人员和徽章标签。也看看学说批处理doctrine-project.org/projects/doctrine-orm/en/2.6/reference/…
-
您应该使用像 XHProf 或 blackfire.io 这样的分析器。这将告诉您代码的哪些部分正在减慢速度,您可以更直接地解决这些问题。作为一般建议,您可能希望避免 Doctrine ORM 并使用 DBAL 来避免不必要的对象水合,例如fpr
$badgeLabel和$developer你不需要实际的对象。如果可能,您可能还希望一次对多个开发人员/徽章执行批处理操作,以减少查询量。这是否有必要在很大程度上取决于您的分析器所说的问题。
标签: php symfony doctrine thephpleague