doctrine2 - 如何提高冲洗效率?
我必须更新我的Doctrine实体以匹配(可能是非常大的)XML文件内部的记录。我还必须根据XML中的数据更新ManyToMany关联。这是我做的一个循环内:doctrine2 - 如何提高冲洗效率?
- 从XML中获取数据
- 从数据库获取实体(如果不存在,创建新)
- 设置新的实体属性
- 获得当前实体协会(吸气返回
ArrayCollection
对象) - 清除所有关联(通过调用
ArrayCollection::clear()
) - 设置新的关联(由子循环中调用
ArrayCollection::add()
) - 通过EntityManager的
坚持实体环路我叫EntityManager::flush()
后。
问题是,刷新会生成大量的查询,而不是一次更新/插入/删除多行。对于每一个实体,执行以下查询:
- 选择从DB
- Update更新实体属性得到实体(这实际上是现在跳过,因为没有性改变......但)
- DELETE清除以前协会
- INSERT插入新的协会 在总计305条记录中XML
,所以我得到915个查询(我想这可能上升到1220个查询,如果所有的实体将发生变化),这使得日进口非常缓慢。
我可以在循环之前利用IdentityMap和预取实体,但仍有UPDATE/DELETE/INSERT查询。
- 有没有办法让flush方法更好地优化查询(使用多重插入,WHERE IN而不是多个DELETE查询等)?
- 这是刷新方法的正常行为还是我做错了什么?
- 也许在如何更新实体关联的方式上存在问题。有更好的方法如何做到这一点? (而不是“获取/清除/添加”方法)
- 我知道该原则不适用于大规模betch处理,但我认为将它用于XML导入是避免数据库不一致的最好方法,可能会出现一种非ORM方法。是对的吗?
- 如果上述方法错误,我该如何解决问题?
你做得很对 - 它只是很慢,因为添加的ORM抽象意味着你不能进行各种你想要的优化。
也就是说,EntityManager确实对事务处理很慢。如果你在一次大的事务中并不是完全需要它们,那么你可以通过flush(),然后每循环20-200次迭代清除EM来获得更高性能的代码。
如果这样不能让您获得足够的性能,那么我可以想到的唯一选择是恢复到直接针对您的DBMS运行自定义SQL的自定义代码。
我知道这不是一个很好的答案,但至少我可以告诉你,你并不疯狂。
------编辑------
来自官方的Doctrine2文章Batch processing:
有些人似乎很奇怪为什么学说不使用 多刀片(...)插入(...)(...),(...),(...),...
首先,该语法只支持mysql和更高版本 postgresql版本其次,没有简单的办法来抓住所有的 当使用 AUTO_INCREMENT或SERIAL时,在这种多插入中生成的标识符,并且ORM需要管理对象的标识符 。最后,插入性能很少是ORM的瓶颈。正常的插入对于大多数情况来说足够快,如果你真的想做快速的大容量插入,那么多重插入不是最好的方式,即Postgres COPY或Mysql LOAD DATA INFILE快几个数量级。
这些是为什么不值得努力实现 抽象,在ORM中执行多重插入mysql和postgresql的原因。
也有使用当远程VS本地数据库作为每个查询发送到远程服务器是相当大的开销,在性能上显著差异。由于事务和数据库优化,使用本地数据库时的开销要低得多。 (例如在问题的例子中70秒降低到300ms)
不知道这是否直接回答了原始海报提出的问题,但希望这可以在冲洗时帮助其他人学习速度问题。
...关于刷新速度,请确保您的xdebug探查器未打开。
[php.ini]
; PROFILING
;xdebug.profiler_enable = 1
;xdebug.profiler_output_name = "cachegrind.out.%t.%s.%p"
;xdebug.profiler_output_dir = "C:\xampp\tmp"
由于这多少影响了我的情况下,原则刷新操作的例子,它是55秒3000条记录,而与探查关闭它为5秒!
+1告诉我我不疯狂:) – 2012-01-03 10:29:45
根据我的研究,如何在仍然使用ORM的情况下更好地优化导入是没有办法的。我已经为潜在的未来谷歌搜索添加了一些信息。 – 2012-01-13 13:31:04
添加$ em-> clear()后,持久性工作得更快,完全解决了我的问题。如果您希望更快插入,请在每次插入查询时禁用索引重建。 $ conn-> prepare('SET autocommit = 0;') - > execute(),并且在查询之后,执行$ conn-> prepare('COMMIT;') - > execute(); – tomazahlin 2014-12-01 19:40:48