php - 使用 symfony 命令导入大量 csv 数据太慢了
问题描述
我需要使用 Symfony 从 myqsl 数据库中的 csv 文件(45 Mo)导入大量数据。我导入了 League\Csv\Reader 库我用学说做了一个命令。它有效,但我很慢。我怎样才能加速这个?
我尝试过了 :
在 $this->em->flush() 之后添加:$this->em->clear();
add : //禁用 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 分钟
解决方案
方法1:(不是最好的)
当flush
方法被调用时,Symfony 会遍历所有的监听器。因此,您可以避免在每个循环上刷新。您可以用以下代码替换每次刷新:
if (0 === ($batchSize++ % $input->getOption('fetch'))) {
$this->entityManager->flush();
$this->entityManager->clear();
}
fetch
选项可以在配置方法中声明:
const BATCH_SIZE = 1000; // As example
/**
* Configure the command.
*/
protected function configure()
{
$this
// the short description shown while running "php bin/console list"
->setDescription('Import a new developper.')
//This option helps you to find a good value and use BATCH_SIZE constant as default
->addOption('fetch', 'f', InputArgument::OPTIONAL, 'Number of loop between each flush', self::BATCH_SIZE)
// the full command description shown when running the command with
// the "--help" option
->setHelp('This command allows you to import a develpper...')
;
方法2:更高效
您可以创建一个命令,该命令使用更新或插入在 sql 文件中写入所有 SQL 查询。然后,您启动一个读取文件并执行查询的本机命令。
方法 3:使用 DBAL 正如评论中所建议的,您可以使用DBAL来避免 Doctrine 不必要的对象水合。
推荐阅读
- c# - SaasTenant 上的扩展无法更新 [ABP 框架]
- scala - Apache Spark 如何实时查看执行程序中的执行(工作)内存?
- keyboard-shortcuts - jupyterlab 键盘快捷键:使用哪个选择器
- r - 选择所有可能的变量组合
- azure - 限制 Azure 应用程序仅向其自身添加/删除用户
- c++ - 在头文件c ++中定义变量
- notepad++ - 在单词的第一个实例之后添加文本(记事本++)
- python - 查找在另一个栅格的每个段内的最大值(一个栅格的)
- postgresql - 使用容器装载但未显示数据库的旧 Postgresql 卷
- salesforce - Salesforce Oauth 2.0 与 Netsuite 的集成