为什么在MongoDB中索引的方向很重要?


114

引用文档

创建索引时,与键关联的数字指定索引的方向,因此它应始终为1(升序)或-1(降序)。方向对于单个键索引或随机访问检索都无关紧要,但是如果您要对复合索引进行排序或范围查询,则方向很重要。

但是,我认为没有理由将索引的方向放在复合索引上。有人可以提供进一步的解释(或示例)吗?

Answers:


111

MongoDB以某种方式连接复合键,并将其用作BTree中的键。

查找单个项目时 -树中节点的顺序无关紧要。

如果要返回一定范围的节点 -彼此靠近的元素将位于树的相同分支下。节点在范围内越近,可以更快地检索它们。

使用单个字段索引 -顺序无关紧要。如果它们以升序排列在一起,则它们也将以降序排列在一起。

当您有复合键时 -顺序开始重要。

例如,如果键是A升序B升序索引可能看起来像这样:

AB行
1 1 1
2 2 6
3 2 7 
4 3 4
5 3 5
6 3 6
7 5 1

对于A升序,B降序的查询,将需要在索引周围跳转,以无顺序返回行,并且查询速度会变慢。例如它将返回Row1, 3, 2, 6, 5, 4, 7

以与索引相同的顺序进行的范围查询将简单地以正确的顺序顺序返回行。

在BTree中查找记录需要O(Log(n))时间。仅按顺序查找一系列记录是OLog(n)+ k,其中k是要返回的记录数。

如果记录混乱,则成本可能高达OLog(n)* k


1
结果行应该是1, 3, 2, 6, 5, 4, 7
johndodo

我仍然认为没有理由让它变慢。只是算法应该不同(对于A中的每个值组,它都应跳到该组的末尾并以相反的顺序进行处理),但是由于MongoDB索引位于内存中,因此对速度没有明显影响。另外,RDBMS对索引的方向一无所知,并且存在相当相似的afaik吗?
johndodo 2012年

8
之所以会影响性能,是因为它不仅是内存中的顺序列表(如简化示例)。它实际上是一棵加权树。乱跳将涉及再次遍历树。RDMS绝对具有索引的顺序。
贾里德·凯尔斯

1
从BTree依次获取节点就像在每个叶子上移动直到用尽然后向上一级和向下一级分支一样简单。O(n)混乱,这会占用更多CPU资源。
贾里德·凯尔斯

感谢您进一步的澄清。我在文档中检查了MySQL索引 -确实可以指定索引方向,但是该设置将被忽略。
johndodo

45

您要寻找的简单答案是,方向仅在您对两个或多个字段进行排序时才重要

如果您在排序{a : 1, b : -1}

指数{a : 1, b : 1}指数{a : 1, b : -1}


1
@MarkPieszak,因为整个排序必须在内存中完成,以使索引无用
Sammaye 2015年

@Sammaye我认为这是正确的主意,尽管我不确定它是否完整。我必须查看实现以了解其实际工作原理,但我认为可以将结果按一个单独的排序拉回,然后需要在内存中进行其他b排序。
Zaid Masud 2015年

1
嗯,上次我检查代码很奇怪,由于排序的原因,它删除了部分排序,但是嗯,也许已经更改了
Sammaye 2015年

如果我进行排序{a: -1, b: -1},应该有{a: -1, b: -1}索引还是{a: 1, b: 1}足够了。
侯赛因

在您的示例中,@ Hussain的{a: 1, b: 1}索引应该足够,因为完全反转索引是可以的。例如,索引on {a: 1}可以用于排序{a: -1}
Zaid Masud

12

为什么索引

了解两个要点。

  1. 虽然索引比没有索引要好,但正确的索引要比任何一个都要好。
  2. MongoDB每次查询将只使用一个索引,从而使复合索引具有适当的字段排序,您可能想使用什么。

索引不是免费的。它们占用内存,并且在执行插入,更新和删除操作时会降低性能。通常,性能的影响可以忽略不计(特别是与读取性能的提高相比),但这并不意味着我们不能聪明地创建索引。

如何编制索引

确定应一起索引哪些字段组是关于了解正在运行的查询。用于创建索引的字段顺序至关重要。好消息是,如果您输入的订单错误,则根本不会使用该索引,因此很容易找到解释。

为什么要排序

您的查询可能需要排序。但是排序可能是一项昂贵的操作,因此将要排序的字段与要查询的字段一样对待是很重要的。因此,如果有索引,它将更快。但是,有一个重要的区别,您要排序的字段必须是索引中的最后一个字段。此规则的唯一例外是,如果该字段也是您的查询的一部分,则必须遵循的最后一条规则不适用。

如何排序

您可以在索引的所有键或子集上指定排序;但是,排序键必须按照它们在索引中出现的顺序列出。例如,索引键样式{a:1,b:1}可以支持{a:1,b:1}上的排序,但不能支持{b:1,a:1}上的排序。

排序必须为其索引键的所有键指定相同的排序方向(即升/降),或为其索引键模式的所有键指定相反的排序方向。例如,索引键模式{a:1,b:1}可以支持{a:1,b:1}和{a:-1,b:-1}上的排序,但不能支持{a:-1 ,b:1}。

假设有以下索引:

{ a: 1 }
{ a: 1, b: 1 }
{ a: 1, b: 1, c: 1 }

Example                                                    Index Used
db.data.find().sort( { a: 1 } )                            { a: 1 }
db.data.find().sort( { a: -1 } )                           { a: 1 }
db.data.find().sort( { a: 1, b: 1 } )                      { a: 1, b: 1 }
db.data.find().sort( { a: -1, b: -1 } )                    { a: 1, b: 1 }
db.data.find().sort( { a: 1, b: 1, c: 1 } )                { a: 1, b: 1, c: 1 }
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } )   { a: 1, b: 1 }

我明白这是一个例子,但如果有索引{ a: 1, b: 1, c: 1 }你真的需要索引{ a: 1}{ a: 1, b: 1}或指数{ a: 1, b: 1, c: 1 }涵盖所有情况?如果查询始终使用相同的排序:1 -1中没有排序
Lukas Liesis

1
如果有许多查询仅在属性“ a”上运行,则使用具有属性“ a”的索引搜索数据库引擎要比通过具有3个属性“ a”,“ b”和“ c”的索引搜索更快。因为索引大小会增加,计数也会增加。例如 书中是否有20章。因此,更快地转到第3章,然后转到特定页面。@LukasLiesis
Somnath Muluk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.