Php 如何高效地将批量数据集插入mysql数据库

Php 如何高效地将批量数据集插入mysql数据库,php,mysql,doctrine,command,symfony5,Php,Mysql,Doctrine,Command,Symfony5,我对symfony5命令类以及如何有效地插入约1000万个条目(只有一个实体具有Uuid字段,并且与其他实体没有任何关系)有一些疑问。整个噱头没有任何用途,只是为了使用elasticsearch运行一些测试才需要 现在,在插入数据时,到目前为止一切正常,但持续数小时(20k/h) ($i=0;$i设置代码(Uuid::v4()); $凭证->设置有效(新日期时间()); $this->em->persist($凭证); $this->em->flush(); } 我应该怎么做(除了去掉我的硬件

我对symfony5命令类以及如何有效地插入约1000万个条目(只有一个实体具有Uuid字段,并且与其他实体没有任何关系)有一些疑问。整个噱头没有任何用途,只是为了使用elasticsearch运行一些测试才需要

现在,在插入数据时,到目前为止一切正常,但持续数小时(20k/h)

($i=0;$i<$numberOfVochers;$i++)的
{
$凭证=新凭证();
$凭证->设置代码(Uuid::v4());
$凭证->设置有效(新日期时间());
$this->em->persist($凭证);
$this->em->flush();
}

我应该怎么做(除了去掉我的硬件:Macbook Pro 2,3 GHz Intel Core i5,8GB)才能更快地完成这项工作?

首先,您可能应该执行批量更新,例如:

for ($i = 0; $i < $numberOfVochers; $i++) {
    $voucher = new Voucher();
    $voucher->setCode(Uuid::v4());
    $voucher->setValid(new DateTime());
      
    $this->em->persist($voucher);
    if ($i % 100) {
        $this->em->flush();
    }
}
$this->em->flush(); // just in case the last badge was not added
($i=0;$i<$numberOfVochers;$i++)的
{
$凭证=新凭证();
$凭证->设置代码(Uuid::v4());
$凭证->设置有效(新日期时间());
$this->em->persist($凭证);
如果($i%100){
$this->em->flush();
}
}
$this->em->flush();//以防万一最后的徽章没有加上
此外,每次刷新后,您应该调用
$this->em->clear()
,以确保不会遇到内存问题。在您的情况下,
$凭证
不依赖以前插入的数据,因此
clear()
不应引起任何问题

由于此操作是批量执行的,您现在可以更新您的命令以分区创建,也就是说,您可以对1/4的凭证启动4次该过程,而不是对所有凭证调用一次您的命令。然后有4个进程执行插入,这通常会提高性能,因为每个进程可以在不同的处理器上运行。在您的情况下,由于每个凭证都可以独立创建,因此这不需要太多工作。在其他情况下,您可能必须调整命令,以便能够正确地划分工作


或者,您也可以在命令中使用线程(不推荐)或使用messenger之类的工具将任务分成多个批,为每个批发送消息,然后使用多个工作进程来处理消息。

有一件事,您可能应该执行批量更新,例如:

for ($i = 0; $i < $numberOfVochers; $i++) {
    $voucher = new Voucher();
    $voucher->setCode(Uuid::v4());
    $voucher->setValid(new DateTime());
      
    $this->em->persist($voucher);
    if ($i % 100) {
        $this->em->flush();
    }
}
$this->em->flush(); // just in case the last badge was not added
($i=0;$i<$numberOfVochers;$i++)的
{
$凭证=新凭证();
$凭证->设置代码(Uuid::v4());
$凭证->设置有效(新日期时间());
$this->em->persist($凭证);
如果($i%100){
$this->em->flush();
}
}
$this->em->flush();//以防万一最后的徽章没有加上
此外,每次刷新后,您应该调用
$this->em->clear()
,以确保不会遇到内存问题。在您的情况下,
$凭证
不依赖以前插入的数据,因此
clear()
不应引起任何问题

由于此操作是批量执行的,您现在可以更新您的命令以分区创建,也就是说,您可以对1/4的凭证启动4次该过程,而不是对所有凭证调用一次您的命令。然后有4个进程执行插入,这通常会提高性能,因为每个进程可以在不同的处理器上运行。在您的情况下,由于每个凭证都可以独立创建,因此这不需要太多工作。在其他情况下,您可能必须调整命令,以便能够正确地划分工作


或者,您也可以在命令中使用线程(不推荐)或使用messenger之类的工具将任务拆分为多个批,为每个批发送消息,然后使用多个工作进程来处理消息。

这实际上取决于表的结构和数据集的大小。你试过禁用索引吗?由于缺少代码,我们无法告诉你这是不是你的代码。然而,@EnricoDias所涉及的是一个因素,如果您将每条记录插入到它自己的事务中,这将导致对每条语句进行几个微小的写操作。暂时禁用索引是一种解决方法,另一种方法是显式打开一个事务来执行这些插入。我们的想法是让mysql将所有微小的写操作汇总到更大、更高效的批处理中。@EnricoDias,该表只包含两个字段,uuid和datetime。没有设置索引。@Sammitch,这是一个简单的for循环,有1000万次迭代,仅此而已。在循环中:$COUNDER=new COUNDER()$凭证->设置代码(Uuid::v4())$凭证->设置有效(新日期时间())$此->em->保存($凭证)$这->em->flush();您是否尝试过将整个操作封装在@Sammitch所说的同一事务中?您还需要考虑存储设备的功能。您将始终受到hd/ssd最大写入速度的限制。这实际上取决于表的结构和数据集的大小。你试过禁用索引吗?由于缺少代码,我们无法告诉你这是不是你的代码。然而,@EnricoDias所涉及的是一个因素,如果您将每条记录插入到它自己的事务中,这将导致对每条语句进行几个微小的写操作。暂时禁用索引是一种解决方法,另一种方法是显式打开一个事务来执行这些插入。我们的想法是让mysql将所有微小的写操作汇总到更大、更高效的批处理中。@EnricoDias,该表只包含两个字段,uuid和datetime。没有设置索引。@Sammitch,这是一个简单的for循环,有1000万次迭代,仅此而已。在循环中:$COUNDER=new COUNDER()$凭证->设置代码(Uuid::v4())$凭证->设置有效(新日期时间())$此->em->保存($凭证)$这->em->flush();您是否尝试将整个操作封装在同一个trans中