我想从XML文件批量导入Doctrine实体。
XML文件可能非常大(最多100万个实体),因此我无法以传统方式持久保存所有实体:
$em->beginTransaction();
while ($entity = $xmlReader->readNextEntity()) {
$em->persist($entity);
}
$em->flush();
$em->commit();
我很快就超出了我的内存限制,并且Doctrine并不是真正设计用来处理那么多托管实体。
我不需要跟踪对持久化实体的更改,只是为了坚持它们;因此,我不希望它们由EntityManager管理。
是否可以在不让EntityManager管理实体的情况下保留实体?
我想到的第一个选择是在坚持之后立即分离它:
$em->beginTransaction();
while ($entity = $xmlReader->readNextEntity()) {
$em->persist($entity);
$em->flush($entity);
$em->detach($entity);
}
$em->commit();
但是,这在Doctrine中相当昂贵,并会减慢导入速度。
另一种选择是使用Connection
对象和预准备语句直接将数据插入数据库,但我喜欢实体的抽象,理想情况下要存储对象直接。
答案 0 :(得分:2)
不是在每次插入后使用detach
和flush
,而是可以批量调用clear
(将所有实体与管理器分离)和flush
显着更快:
Doctrine中的批量插入最好分批进行 一个事务性的后写行为的优点 EntityManager的。以下代码显示了插入10000的示例 批量大小为20的对象。您可能需要尝试使用 批量大小,以找到最适合您的大小。批量较大 大小意味着内部更准备的语句重用,但也意味着更多 在冲洗期间工作。
https://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html
如果可能,我建议避免批量操作的交易,因为它们往往会减慢速度:
//$em->beginTransaction();
$i = 0;
while ($entity = $xmlReader->readNextEntity()) {
$em->persist($entity);
if(++$i % 20 == 0) {
$em->flush();
$em->clear(); // detaches all entities
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->clear();
//$em->commit();