我有可以执行的下一个代码,但是它花费了太多时间...有什么方法可以用createQueryBuilder和update方法来优化它?
这是当前功能:
private function getCsv()
{
$file = 'Diva_tarif.csv';
Message::write("Retriving $file", 3);
$file = $this->root_data . $file;
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder(';')]);
$counter = 0;
$batch_size = 30;
if (($handle = fopen($file, 'r')) !== false) {
$header = fgets($handle);
while (($line = fgets($handle)) !== false) {
$line = $serializer->decode($header . $line, 'csv');
$repo = $this->em->getRepository(Article::class);
if(isset($line['DOS'])){
$counter ++;
$arts = $repo->findBy(array('dos' => $line['DOS'], 'ref' => $line['REF']));
$used_metas = [
'TACOD',
'VENUN',
'DEV',
'PUB',
'ALZTXREMMAX',
'ALZTXREMMAXLALPHA',
];
foreach($arts as $art){
foreach ($used_metas as $metakey ) {
$meta_obj = new ArticleMeta();
$meta_obj->setName($metakey);
$meta_obj->setValue($line[$metakey]);
$meta_obj->setArticle($art);
$this->em->persist($meta_obj);
}
}
if (($counter % $batch_size) === 0) {
$this->em->flush();
$this->em->clear();
}
if(($counter % 500) == 0){
Message::write("$counter lines added", 4);
}
}
}
Message::write("$counter lines added", 4);
Message::write("Done", 3);
$this->em->flush();
$this->em->clear();
fclose($handle);
}
}
目标是获取文章并为ArticleMeta分配新的值。 有想法吗?
答案 0 :(得分:1)
您可以直接使用CsvEncoder
,而无需使用序列化器,而无需解码即可使用解码。
我区分了两种提高效果的方法
您应该将ref-dos
对索引到数据库中,这确实会增加查询时间。
但是执行脚本的时间会随着文件的行数而增加。
您可以解析一次文件,提取所有dos
和ref
,然后用成对的ref-dos
构建一个数组。
示例:[ABCD-1234
,BCDE-2345
,...]
此后,您可以对数据库进行ONE
个大查询,并且避免了一个查询/一行,这意味着IMO非常耗时。
这种方式与行数的关系较少,因为您只查询数据库一次。
这样IMO是最好的
此外,您可以在while之外声明$used_metas
和$repo
。
您已经在使用批处理+实体管理器清理,这是在使用Doctrine插入许多实体时的一种好方法。
如果您真的想快一点,可以使用原始SQL并避免准则实体的水化。但是我不建议您这样