MongoDB Update-Upsert性能障碍(性能从悬崖上掉下来)

时间:2014-02-27 18:49:49

标签: python performance mongodb upsert

作为一些性能评估的一部分,我正在执行重复更新操作以将文档添加到MongoDB中。基于我正在执行的更新(w / upserts)的数量,我发现了执行时间的巨大非线性:

在Python中使用以下命令循环...

collection.update({'timestamp': x}, {'$set': {'value1':y, v1 : y/2, v2 : y/4}}, upsert=True)

给我这些结果......

500 document upserts 2 seconds.
1000 document upserts 3 seconds.
2000 document upserts 3 seconds.
4000 document upserts 6 seconds.
8000 document upserts 14 seconds.
16000 document upserts 77 seconds.
32000 document upserts 280 seconds.

请注意,在8k文档更新后,性能开始迅速降低,并且通过32k文档更新,我们看到吞吐量降低了6倍。为什么是这样?看起来奇怪的是,连续8次“手动”运行4k文档更新比使用Python连续执行它们快6倍。

我已经看到在mongostats中我获得了一个可笑的高锁定db比率(> 100%)和 当它运行时,top显示我> 85%的CPU使用率。我有一个i7处理器,可以为VM提供4个内核。

1 个答案:

答案 0 :(得分:11)

您应该在“timestamp”字段中添加升序索引:

collection.ensure_index("timestamp")  # shorthand for single-key, ascending index

如果此索引应包含唯一值:

collection.ensure_index("timestamp", unique=True)

由于规范未编入索引且您正在执行更新,因此数据库必须检查集合中的每个文档,以查看是否已存在该规范的任何文档。当你为500个文档(在一个空白集合中)执行此操作时,效果并不是那么糟糕......但是当你为32k执行此操作时,它会执行类似的操作(在最坏的情况下):

文件1 - 假设空白收集,肯定会插入

文件2 - 检查文件1,更新或插入

文件3 - 检查文件1-2,更新或插入

...等...

文件32000 - 检查文件1-31999,更新或插入

添加索引时,数据库不再需要检查集合中的每个文档;相反,它可以使用索引来使用B树游标而不是基本游标更快地找到任何可能的匹配。

您应该使用和不使用索引来比较collection.find({"timestamp": x}).explain()的结果(请注意,您可能需要使用hint()方法强制它使用索引)。关键因素是您必须迭代的文档数量(explain()的“nscanned”结果)与您的查询匹配的文档数量(“n”键)。如果数据库只需要准确扫描匹配或接近匹配的内容,那就非常有效;如果您扫描32000个项目但只找到1个或少数几个匹配项,那效率非常低,特别是如果db必须为每个upsert 执行类似的操作

由于您未在multi=True调用中设置update,因此您需要仔细检查 - 如果更新操作找到匹配的文档,则会更新它并且不会继续检查整个系列。

很抱歉链接垃圾邮件,但这些都是必读内容:

http://docs.mongodb.org/manual/core/indexes/

http://api.mongodb.org/python/current/api/pymongo/collection.html#pymongo.collection.Collection.ensure_index

http://api.mongodb.org/python/current/api/pymongo/collection.html#pymongo.collection.Collection.update

http://docs.mongodb.org/manual/reference/method/cursor.explain/