我必须更新我的Doctrine实体以匹配(potentionaly very large)XML文件中的记录。我还必须根据XML中的数据更新ManyToMany关联。这就是我在循环中所做的事情:
ArrayCollection
对象)ArrayCollection::clear()
)ArrayCollection::add()
) 在循环之后,我致电EntityManager::flush()
。
问题是刷新会产生大量查询,而不是一次更新/插入/删除多行。对于每个实体在查询后执行:
因此,对于XML中的305条记录,我总共获得了915条查询(我想如果所有实体都会更改,最多可能会有1220条查询),这会导致导入非常慢。
我可以在循环之前利用IdentityMap和预取实体,但仍然有UPDATE / DELETE / INSERT查询。
答案 0 :(得分:32)
你做得对 - 它只是很慢,因为增加的ORM抽象意味着你不能进行你想要的各种优化。
也就是说,EntityManager在大的事务上确实变慢了。如果你在一个大事务中并不是绝对需要它们,你可以通过flush()获得更高性能的代码,然后每20-200次迭代循环清除()EM。
如果这不能提供足够的性能,我能想到的唯一选择是恢复到直接针对您的DBMS运行自定义SQL的自定义代码。
我知道这不是一个好的答案,但至少我可以告诉你,你并不疯狂。
------编辑------
来自Batch processing上的官方Doctrine2文章:
有些人似乎在想为什么Doctrine不使用 多插入(插入(...)值(...),(...),(...),...
首先,只有mysql和更新版本支持此语法 postgresql版本。其次,没有简单的方法来掌握所有 使用时在这样的多插入中生成的标识符 AUTO_INCREMENT或SERIAL和ORM需要标识符以进行标识 管理对象。最后,插入性能很少 ORM的瓶颈。普通插入物的速度足够快 大多数情况下,如果你真的想做快速批量插入,那么a 多插入不是最好的方式,即Postgres COPY或Mysql LOAD DATA INFILE快几个数量级。
这就是为什么不值得努力实施的原因 抽象,在mysql和postgresql上执行多插入 ORM。
使用远程与本地数据库时,性能也存在显着差异,因为将每个查询发送到远程服务器的开销非常大。由于事务和数据库优化,使用本地数据库时开销要低得多。 (例如,在问题中的示例情况下,70秒降低到300毫秒)
答案 1 :(得分:4)
不确定这是否能直接回答原始海报提出的问题,但希望这可以帮助其他人在冲洗时解决Doctrine速度问题。
...关于冲洗速度,请确保您的xdebug探测器未打开。
[php.ini]
; PROFILING
;xdebug.profiler_enable = 1
;xdebug.profiler_output_name = "cachegrind.out.%t.%s.%p"
;xdebug.profiler_output_dir = "C:\xampp\tmp"
作为一个示例,在我的情况下,这对Doctrine刷新操作有多大影响,3000条记录为55秒,而关闭探测器则为5秒!