使用索引在MongoDB中运行时间

3

基于 MongoDB 文档

ensureIndex() 函数仅在索引不存在时创建索引。

一旦集合上的键被索引,与指定键匹配的查询表达式的随机访问速度很快。如果没有索引,MongoDB 必须检查查询中指定键的每个文档的值:

db.things.find({j:2});  // fast - uses index
db.things.find({x:3});  // slow - has to check all because 'x' isn't 

这是否意味着第一行代码的运行时间为big_theta = 1,而第二行代码的运行时间为big_theta = n

@SergioTulentsev 你应该发布为答案,并获得积分! :) - LaneLane
@LaneLane:太晚了,已经有答案了 :) - Sergio Tulentsev
3个回答

10

MongoDB使用B树进行索引,可以在index.cpp的源代码中看到。这意味着查询可以表示为O(log N),其中N是文档的数量,但如果D是树的深度(假设树有一定的平衡性),则其也为 O(D)。D通常非常小,因为每个节点都会有很多子节点。

MongoDB中每个节点的子节点数量约为8192 (btree.h),因此拥有几十亿文档的索引可能只需要3层的树!您很容易意识到对数不是log_2(如二叉树),而是log_8192,其增长非常缓慢。

因此,B树通常被视为实践中的常数时间查找,即O(1)

在每个节点中保留许多子节点的另一个好处是,索引存储在磁盘上。您想尝试利用磁盘块中的所有空间来提高缓存性能并减少磁盘寻道。B树具有非常好的磁盘性能,因为您只需要访问非常少的节点即可找到您要查找的内容。


作为开发者,有没有办法确保每个节点都有许多子节点,或者这是由MongoDB完成的? - bouncingHippo
这是通过btree实现完成的。我没有专门研究过MongoDB(除了为此帖子浏览源代码),但他们是聪明的人,所以我猜他们在平衡和分配方面做了一些工作。 - Emil Vikström
在答案中编辑了含糊不清的陈述。这不是O(1)查找。请参见:http://en.wikipedia.org/wiki/B-tree - Manav Kataria
1
Manav,如果你仔细阅读我的回答,你会发现我对我的陈述进行了解释。我已经明确表示这是一个对数函数,但增长非常缓慢。因此,编辑它将完全改变回答的意图。相反,请给出你认为正确的答案点赞即可。(但请记住,大多数人永远不会在每个节点具有8k个子节点的平衡B树中达到4个层级,更不用说五个或六个了。所以,在这里对数函数真的重要吗?)我也可以依靠权威性:我的动机来自于我在乌普萨拉大学的数据库教授们的观点 :-) - Emil Vikström

3
Mongo索引是B树,因此索引查找的时间复杂度为O(log n)。未索引的查找的时间复杂度为O(n)

有没有办法进一步减少索引查找的运行时间? - LaneLane
减少_n_。除此之外,没有。 - Chris Heald

0

B-树的时间复杂度是O(log N),Emil Vikström的答案O(1)是错误的。即使在他的“动机”(或假设)下,也是错误的:他忘记了搜索每个节点的8192个子节点所需的时间。换句话说,如果K是节点大小,D是树的深度,则时间复杂度可以重新表示为O(D) + O(log K)(相当于O(log N)),如果子节点以BST或类似的对数结构组织。


2
你在数学上是正确的,这也是我回答时开头所说的。我的动机是,在实践中,精确的渐近运行时间是无关紧要的。你可以用21个级别索引已知宇宙中的所有原子。我没有忽略搜索子节点的时间,该数字是有界的,因此在每个节点中为O(1)。 - Emil Vikström

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接