我正在许多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();
}
在这种情况下,每行所有程序大约需要5秒钟!
现在如果我像这样添加setMaxResults:
$qb = $this->entityManager->createQueryBuilder();
$flows = $qb->select('flow')
->from('AppBundle:FlowAndata', 'flow')
->setMaxResults(100)
->getQuery()
->getResult();
花了不到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();
}
通过这种方式,我创建了许多分为100行的查询。 是一个好的做法还是有更好的方法来解析很多行并插入它?
答案 0 :(得分:4)
official documentation of Doctrine建议的有效方式是利用EntityManager
的事务性后写行为。
迭代数据处理的大结果
您可以使用
iterate()
方法迭代大结果而不是UPDATE或DELETE意图。从IterableResult
返回的$query->iterate()
实例实现了Iterator接口,因此您可以使用以下方法处理大结果而不会出现内存问题。 (See example)
批量插入
Doctrine中的批量插入最好分批执行,利用
EntityManager
的事务性后写行为。 [...]您可能需要尝试批量大小以找到最适合您的尺寸。较大的批量大小意味着内部更准备的语句重用,但也意味着flush
期间的更多工作。 (See example)
混合两种技术的版本(Inside Entity Repository):
$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();