从一个存储库到另一个存储库的 Symfony 大量水合作用
Symfony mass hydration from one repository to another
我有下一个代码可以正常执行,但它需要太多时间...有什么方法可以使用 createQueryBuilder 和更新方法优化它吗?
这是当前函数:
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);
}
}
objective是获取Article并为ArticleMeta赋值。
有什么想法吗?
您可以直接使用 CsvEncoder
而无需序列化器,您正在使用没有反规范化的解码。
我区分了两种提高性能的方法
无代码更改
您应该将 ref-dos
对索引到您的数据库中,这确实会增加查询时间。
但是执行脚本的时间会随着文件行数的增加而增加。
一个大查询
您可以解析一次文件,提取所有 dos
和 ref
,然后用 ref-dos
.
对构建一个数组
示例:[ABCD-1234
、BCDE-2345
、...]
之后你可以对你的数据库进行 ONE
大查询,避免 query/line,IMO 非常耗时。
这种方式与行数关系不大,因为你只查询一次数据库。
这种方式IMO是最好的
此外,您可以在 while 之外声明 $used_metas
和 $repo
。
您已经在使用批处理 + 实体管理器清理,这是使用 Doctrine 插入许多实体的好方法。
如果你真的想快速进行,你可以使用原始 SQL 并避免学说实体水合作用。但是我不推荐你这样
我有下一个代码可以正常执行,但它需要太多时间...有什么方法可以使用 createQueryBuilder 和更新方法优化它吗?
这是当前函数:
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);
}
}
objective是获取Article并为ArticleMeta赋值。 有什么想法吗?
您可以直接使用 CsvEncoder
而无需序列化器,您正在使用没有反规范化的解码。
我区分了两种提高性能的方法
无代码更改
您应该将 ref-dos
对索引到您的数据库中,这确实会增加查询时间。
但是执行脚本的时间会随着文件行数的增加而增加。
一个大查询
您可以解析一次文件,提取所有 dos
和 ref
,然后用 ref-dos
.
示例:[ABCD-1234
、BCDE-2345
、...]
之后你可以对你的数据库进行 ONE
大查询,避免 query/line,IMO 非常耗时。
这种方式与行数关系不大,因为你只查询一次数据库。
这种方式IMO是最好的
此外,您可以在 while 之外声明 $used_metas
和 $repo
。
您已经在使用批处理 + 实体管理器清理,这是使用 Doctrine 插入许多实体的好方法。
如果你真的想快速进行,你可以使用原始 SQL 并避免学说实体水合作用。但是我不推荐你这样