MongoDB中,索引支持查询的执行。如果没有索引,MongoDB为了选出符合查询语句的文档,必须进行一个集合扫描,即扫描集合中的每个文档。如果存在适合查询的索引,MongoDB能用索引来限制其必须检查的文档数。
索引是按照容易遍历形式存储一小部分集合数据的特殊数据结构。索引存储一个或多个特定域的值,并按照该域进行排序。索引项的有序支持高效等值匹配和基于范围的查询操作。此外,MongoDB能通过利用索引顺序返回有序结果。
根本上,MongoDB的索引域其他数据库系统的索引类似。MongoDB在集合级别定义索引,支持MongoDB集合中文档任何域或子域上的索引。
一.默认_id索引
MongoDB在集合创建期间会在_id域上创建一个唯一索引。_id索引阻止客户插入_id域值相同的两个文档。该_id域上的索引也不能删除。
--注:
1)分片簇中,如果没用_id域作为分片键,那么,应用必须确保_id域值的唯一性以防发生错误。这通常用标准的自动产生的ObjectId来实现。

二.创建索引
1)索引创建
为了通过MongoDB Shell创建索引,使用db.collection.createIndex()。
db.collection.createIndex( <key and index type specification>, <options> )
下述例子在name域上创建一个降序的单键索引:
db.collection.createIndex( { name: -1 } )
db.collection.createIndex方法在不存在同样指定的索引时对其进行创建。
--注:
1)MongoDB索引采用B-tree数据结构。
2)索引名字
索引的默认名字为索引域与其排序方向(即1或-1)通过下划线作为分隔符的联合。例如:{item:1,quantity:-1}上创建的索引名字为item_1_quantity_-1。
您也可以定制索引的名字,像比默认名字更可读的名字。例如:考虑应用频繁查询produects集合来填充已有inventory的数据。下述createIndex()方法在item和quantity上创建了一个名字为"query for inventory"的索引。
db.products.createIndex({ item: 1, quantity: -1 } ,{ name: "query for inventory" })
您可以用db.collection_getIndex()方法查看索引名字。一旦创建不能对索引进行重命名。相反,您必须将其删除再用新名字进行重建。

三.索引类型
MongoDB提供多种不同类型的索引支持确定类型的数据和查询。
1.单域索引(Single Field)
除了MongoDB定义的_id索引,MongoDB支持在文档单域上创建用户定义的升序或降序索引。
对单域索引和排序操作,因为MongoDB能在任一方向上移动,所以,索引键的排序顺序(即升序或降序)没什么关系。
2.复合索引(Compound Index)
MongoDB也支持在多个域上用户定义的索引,即复合索引。
复合索引中域的顺序很重要。例如:如果一个复合索引包括{userid:1,score:-1},索引先对userid进行排序,然后,在每个userid值中对score进行排序。
对复合索引和排序操作,索引键的排序顺序(即升序或降序)决定是否支持一个排序操作。
3.多键索引(Multikey Index)
MongoDB用多键索引来对数组中存储的内容进行索引。如果对包含一个数组值得域进行索引,MongoDB为数组的每个元素创建单独的索引项。这些多键索引允许查询通过匹配数组元素选择包含数组的文档。如果索引域包含数组值,MongoDB自动决定是否创建一个多键索引;您不必显式确定多键索引类型。
4.地理空间索引(Geospatial Index)
为了支持地理空间坐标数据的高效查询,MongoDB提供两种特殊索引:当返回结果时用平面几何图形的2d索引和用球面几何图形返回结果的2dsphere索引。
5.文本索引(Text Indexes)
MongoDB提供支持对集合中字符串内容进行搜索的文本索引类型。该文本索引并不存储特定语言的终止词(例如:"the","a","or")和并对集合中的词进行词干处理以只存储根词。
6.哈希索引(Hashed Indexes¶)
为了支持基于哈希的分片,MongoDB提供了一种哈希索引类型,其对域值的哈希值进行索引。该类型索引能对数值范围进行更好的随机分布,但其只支持等值匹配且不支持基于范围的查询。

四.索引属性
1.唯一索引(Unique Indexes)
索引的唯一属性导致MongoDB拒绝索引域值重复的文档。除了唯一约束,为索引功能上与其他索引可以交换。
2.部分索引(Partial Indexes)
部分索引最早在MongoDB 3.2版本引入。部分索引仅对集合中符合特定过滤表达式的文档进行索引。通过对集合中文档子集进行索引,部分索引降低了存储需求和索引创建和维护的成本。
部分索引提供稀疏索引(sparse indexes)功能的超集且比稀疏索引更受欢迎。
3.稀疏索引(Sparse Indexes)
索引的稀疏属性确保索引只包含有索引域的文档的索引项。索引跳过并不包含索引域的文档。
您可以将稀疏索引与唯一索引组合以阻止插入索引域有重复值的文档,并跳过没有索引域的文档。
4.TTL索引(TTL Indexes)
TTL索引是MongoDB能用来自动从集合删除超过某一时间的文档的特殊索引。这对类似机器产生的、只需在库中存在有限时间的事件数据、日志和会话信息等某种类型的信息是最理想的。
5.隐藏索引(Hidden Indexes)
隐藏索引最早出现于MongoDB4.4版本。隐藏索引对查询计划器是不可见的,不能用于支持查询。
通过对查询计划器隐藏一个索引,用户能评估删除一个索引带来的潜在影响而并没实际删除索引。如果删除索引有负面影响,用户还能让索引再变的可见而非必须重建删除的索引。因为索引隐藏期间会被完全维护,一旦变得可见将会立即可用。
除了_id索引,可以隐藏任何索引。
6.索引使用(Index Use)
索引能提高读操作的效率。Analyze Query Performance教程将提供有和没有索引时查询执行统计的例子。
7.索引和排序规则(Collation)
该特性最早出现于MongoDB 3.4版本。排序规则允许用户指定特定语言的字符比较规则,像字母大小写和重音符号的规则。
为了用索引进行字符比较,操作也必须确定同样的排序规则。即,一种排序规则的索引不能支持指定了不同排序规则的、在该索引域上进行的字符比较操作。
例如:集合myColl有一个排序规则locale为"fr"的字符域category上的索引。
db.myColl.createIndex( { category: 1 }, { collation: { locale: "fr" } } )
下述查询操作指定了与索引相同的排序规则,因此,能使用该索引:
db.myColl.find( { category: "cafe" } ).collation( { locale: "fr" } )
但是,下述查询操作默认使用了"simple"二进制排序规则,因此,不能用该索引:
db.myColl.find( { category: "cafe" } )
索引前缀键不是字符、数组和嵌入文档的复合索引,指定不同排序规则的操作还是能使用该索引以支持该索引前缀键上的比较。
例如:集合myColl在数字域score、price和字符域category上有一个复合索引;该索引以排序规则locale"fr"创建以进行字符比较
db.myColl.createIndex({ score: 1, price: 1, category: 1 },{ collation: { locale: "fr" } } )
下述操作,其使用"simple"二进制排序规则用于字符比较,但能使用该索引:
db.myColl.find( { score: 5 } ).sort( { price: 1 } )
db.myColl.find( { score: 5, price: { $gt: NumberDecimal( "10" ) } } ).sort( { price: 1 } )
下述操作,其使用了"simple"二进制排序规则用于索引域category上的字符比较,能用索引完成查询的score:5部分:
db.myColl.find( { score: 5, category: "cafe" } )
下述索引只支持简单二进制比较,并不支持排序规则:
1)文本索引;
2)2d索引;
3)geoHaystack索引。

五.覆盖查询(Covered Queries)
当查询规则和投影仅包括索引域时,MongoDB直接从该索引返回结果而无需扫描任何文档并将其读入内存。这些覆盖查询可能很高效。

六.索引交集(Index Intersection)
MongoDB能用索引交集来完成查询。对指定了复合查询条件的查询,如果一个索引能完成部分查询条件,而另一个索引能完成另一部分查询条件,那么,MongoDB能用两个索引的交集完成该查询。复合索引还是索引交集哪个更高效,这取决于特定查询和系统。

七.限制条件
索引会有某些限定条件,像索引键的长度或每个集合上索引的数目等。

八.其他考量
虽然索引能提高查询性能,索引也会出现一些操作考量。
应用也许遇到索引创建期间性能降低,包括对集合访问的限制等。
某些驱动可以指定索引,指定NumberLong(1)而非1,这对最终索引并没任何影响。