Doctrine插入了许多数据

Ale*_*eri 9 php mysql doctrine symfony doctrine-orm

我正在努力在许多csv中导入300000行.

首先,我使用csv并将每一行导入到数据库中的一个表中.

在我想要解析所有行并插入到右表中时,该数据与某些关系.

所以我试过这个:

    $qb = $this->entityManager->createQueryBuilder();
    $flows = $qb->select('flow')
        ->from('AppBundle:FlowAndata', 'flow')
        ->getQuery()
        ->getResult();

    $countRows = 0;
    foreach ($flows as $row) {
         //some check 
         $entity = new TestTable();
         $entity->setCode($row->getCode());
         //many other fields
         $this->entityManager->persist($entity);
         $this->entityManager->flush();
    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,每行所有程序大约需要5秒!

现在如果我像这样添加setMaxResults:

    $qb = $this->entityManager->createQueryBuilder();
    $flows = $qb->select('flow')
        ->from('AppBundle:FlowAndata', 'flow')
        ->setMaxResults(100)
        ->getQuery()
        ->getResult();
Run Code Online (Sandbox Code Playgroud)

花了不到1秒!

所以我想要获取所有行并将其拆分为setMaxResult的递归函数,如下所示:

    $qb = $this->entityManager->createQueryBuilder();
    $flows = $qb->select('flow')
        ->from('AppBundle:FlowAndata', 'flow')
        ->getQuery()
        ->getResult();

    $countFlows = count($flows);
    $numberOfQuery = $countFlows / 100;

    for ($i = 0; $i <= $numberOfQuery; $i++) {
         $this->entityManager->clear();
         $qb = $this->entityManager->createQueryBuilder();
         $flows = $qb->select('flow')
            ->from('AppBundle:FlowAndata', 'flow')
            ->setFirstResult($i * 100)
            ->setMaxResults(100)
            ->getQuery()
            ->getResult();

    }
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我创建了许多分为100行的查询.是一个好的做法还是有更好的方法来解析很多行并插入它?

yce*_*uto 6

Doctrine官方文档推荐的有效方法是利用的事务性事务后写行为EntityManager

迭代大结果以进行数据处理

您可以使用该iterate()方法来迭代较大的结果,而无需执行UPDATE或DELETE意图。IterableResult从返回的实例$query->iterate()实现Iterator接口,因此您可以使用以下方法处理大量结果而不会出现内存问题。(请参见示例

批量插入

充分利用Doctrine的批量插入,最好利用的事务性事务后写行为EntityManager。[...]您可能需要尝试批量大小以找到最适合您的大小。较大的批处理量意味着内部将有更多的准备好的语句重用,但也意味着在此期间需要进行更多的工作flush。(请参见示例

版本混合两种技术(内部实体存储库中):

$q = $this->_em->createQuery('SELECT f FROM AppBundle:FlowAndata f');
$iterableResult = $q->iterate();

$i = 0;
$batchSize = 100;

foreach ($iterableResult as $row) {
    // do stuff with the data in the row, $row[0] is always the object 
    /** @var AppBundle\Entity\FlowAndata $flow */
    $flow = $row[0];

    //some check 
    $entity = new TestTable();
    $entity->setCode($row->getCode());
    //many other fields

    $this->_em->persist($entity);

    $i++;
    if (($i % $batchSize) === 0) {
        $this->_em->flush();
        // Detaches all objects from Doctrine!
        $this->_em->clear(); 
    } else {
        // detach from Doctrine, so that it can be Garbage-Collected immediately
        $this->_em->detach($flow);
    }
}

$this->_em->flush(); //Persist objects that did not make up an entire batch
$this->_em->clear();
Run Code Online (Sandbox Code Playgroud)

  • 太棒了,它的工作速度更快!谢谢 (2认同)