我正在用Symfony 4 + Doctrine构建一个应用程序,人们可以在其中上载大的CSV文件,然后将这些记录存储在数据库中。插入之前,我正在检查条目是否不存在...
在仅包含1000条记录的示例CSV文件中,不带索引需要16秒,带索引需要 8秒(MacBook 3Ghz-16 GB内存)。我的直觉告诉我,这很慢,应该在<1秒内完成,尤其是对于索引。
在电子邮件列上设置索引。
我的代码:
$ssList = $this->em->getRepository(EmailList::class)->findOneBy(["id" => 1]);
foreach ($csv as $record) {
$subscriber_exists = $this->em->getRepository(Subscriber::class)
->findOneByEmail($record['email']);
if ($subscriber_exists === NULL) {
$subscriber = (new Subscriber())
->setEmail($record['email'])
->setFirstname($record['first_name'])
->addEmailList($ssList)
;
$this->em->persist($subscriber);
$this->em->flush();
}
}
我的问题:
如何加快此过程?
答案 0 :(得分:1)
LOAD DATA INFILE具有IGNORE
和REPLACE
选项,如果您在UNIQUE KEY
列上放置PRIMARY KEY
或email
,则可以处理重复项。
Look at settings用于加快导入速度。
答案 1 :(得分:0)
就像Cid所说的那样,将flush()移到循环外或在循环内放置一个批处理计数器,并且仅以一定的间隔在循环内刷新
$batchSize = 1000;
$i = 1;
foreach ($csv as $record) {
$subscriber_exists = $this->em->getRepository(Subscriber::class)
->findOneByEmail($record['email']);
if ($subscriber_exists === NULL) {
$subscriber = (new Subscriber())
->setEmail($record['email'])
->setFirstname($record['first_name'])
->addEmailList($ssList)
;
$this->em->persist($subscriber);
if ( ($i % $batchSize) === 0) {
$this->em->flush();
}
$i++;
}
}
$this->em->flush();
或者,如果仍然很慢,则可以抓住Connection $this->em->getConnection()
并按照以下说明使用DBAL:https://www.doctrine-project.org/projects/doctrine-dbal/en/2.8/reference/data-retrieval-and-manipulation.html#insert