MongoDB-Indexes索引

indexes索引

索引能让MongoDB查询变得更加高效,如果没有索引,MongoDB就需要扫描集合中的所有文档,然后再将每个文档进行匹配,选出匹配成功的文档。如果在查询中能够适当地使用索引,那么MongoDB就可以利用该索引去限制查询文档的个数,从而提交查询效率。
索引以一种特殊的数据格式存储,它以一种易于遍历的形式存储了集合数据集的一小部分。索引存储着一个特定字段的值或者一些系列字段的值,并按照字段的值排序。索引项的排序支持高效的相等匹配和基于范围的查询操作。此外,MongoDB可以通过使用索引中的排序来返回排序的结果。
notion image
如上图所示,索引将score按升序排序,当使用范围查询时可以很高效地匹配结果并按照规定顺序返回。
需要注意的是,虽然索引可以使查询更加高效,但是索引本身会存储一定的空间,因此索引并不是越多越好,应当适当地使用索引。
MongoDB默认为_id创建索引,并添加唯一性约束(unique)。
 

索引管理

创建索引

语法

shell中通过createIndex来创建索引。
语法:
db.collection.createIndex( <key and index type specification>, <options> )
示例:
db.collection.createIndex( { name: -1 } )
这条语句创建了一个name字段的索引,并按照降序排序。
name表示为文档字段name创建索引,-1表示按降序排序,除此之外也可以传入1,表示升序排序。
db.collection.createIndex() 只能创建索引,如果之前存在相同规则的索引,则该语句将不起作用。

索引名称

如果没有显示指明索引名,MongoDB会自动生成索引名,
格式: ${name}_${value}
例如上面的db.collection.createIndex( { name: -1 } ) ,创建的索引名就是name_-1
一旦索引被创建,就不能再重命名。
创建索引时显示指定索引名称的语法示例如下:
db.products.createIndex( { item: 1, quantity: -1 } , { name: "query for inventory" } )

获取索引

可以通过db.collection.getIndexes() 来获取集合中的索引。但是需要注意,一旦索引被创建,就不能重命名,

删除索引

db.collection.dropIndex() // Removes a specified index on a collection. db.collection.dropIndexes() // Removes all indexes on a collection.
 

索引API参考

Name
Description
Builds an index on a collection.
Removes a specified index on a collection.
Removes all indexes on a collection.
Returns an array of documents that describe the existing indexes on a collection.
Rebuilds all existing indexes on a collection.
Reports the total size used by the indexes on a collection. Provides a wrapper around the totalIndexSize field of the collStats output.
Reports on the query execution plan for a cursor.
Forces MongoDB to use a specific index for a query.
Specifies an exclusive upper index bound for a cursor. For use with cursor.hint()
Specifies an inclusive lower index bound for a cursor. For use with cursor.hint()

索引类型

MongoDB提供了许多不同的索引类型来支持特定类型的数据和查询。

单字段索引(Single Field Indexes)

对于单字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任意方向遍历索引。
单字段索引是最简单的索引,它能提高等值查询和范围查询的效率。
db.records.createIndex( { score: 1 } ) // 建立单字段索引 db.records.find( { score: 2 } ) // 等值查询 db.records.find( { score: { $gt: 10 } } ) // 范围查询
如果是嵌套文档,则可以通过.来选中嵌套文档的字段。
{ "_id": ObjectId("570c04a4ad233577f97dc459"), "score": 1034, "location": { state: "NY", city: "New York" } } db.records.createIndex( { "location.state": 1 } )
另一种情况是为嵌套文档整体建立索引,这在查询整个嵌套文档时非常有效。
{ "_id": ObjectId("570c04a4ad233577f97dc459"), "score": 1034, "location": { state: "NY", city: "New York" } } db.records.createIndex( { location: 1 } ) // 查询嵌套文档 db.records.find( { location: { city: "New York", state: "NY" } } )
注意这里是

复合索引(Compound Indexes)

MongoDB支持复合索引。假设这样的一个文档结构:
{ userid: 'aa1', score: 45 }
为其建立符合索引后,索引存储结构如下图所示:
notion image
需要注意地是,MongoDB限制每个复合索引最多包含32个字段。

匹配全部或者一部分字段

复合索引既可以用于所有字段的匹配,也可以用于单个字段的匹配:
db.products.find( { userid: "aa1" } ) db.products.find( { userid: "ca2", score: { $gt: 5 } } )

创建复合索引

创建复合索引的语法和创建单字段索引非常类似:
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
示例:
db.collection.createIndex({userid: 1, score: -1})

顺序

在单字段索引中,顺序并不是那么的重要,因为MongoDB可以在任何方向上遍历索引,但是在复合索引中,字段顺序是非常重要的,它会影响索引的性能。
db.events.createIndex( { "username" : 1, "date" : -1 } ) // 支持 db.events.find().sort( { username: 1, date: -1 } ) db.events.find().sort( { username: -1, date: 1 } ) // 不支持 db.events.find().sort( { username: 1, date: 1 } )
 

多键索引(MultiKey Indexes)

如果为数组类型的字段建立索引,那么MongoDB就会为数组中每个元素创建索引键,这就是多键索引。多键索引支持高效地查询数组字段。
notion image

创建多键索引

创建多键索引和创建单字段索引的方式相同,只不过创建多键索引时,字段是一个数组。
如果在创建索引时,字段是一个数组,那么MongoDB将会自动为其创建多键索引,无需用户去明确地指定多键类型。
db.collection.createIndex( { <field>: < 1 or -1 > } )
 

地理空间索引(Geospatial Indexes)

MongoDB支持建立地理空间数据,MongoDB为其提供两种特别的索引:2d indexes2dsphere indexes

文本索引(Text Indexes)

MongoDB提供文本索引来更高效地实现文本查询。文本索引可以用于任何值为字符串或字符串数组的字段。
一个集合中只能由一个文本搜索索引,但是这个文本搜索索引可以覆盖多个字段。

创建文本索引

创建文本索引的语法和创建复合类型非常相似,但是value是一个字符串。
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
示例:
db.reviews.createIndex( { comments: "text" } ) // 多个字段 db.reviews.createIndex( { subject: "text", comments: "text" } )
当文本索引包含多个字段时,根据复合索引的特点我们知道,此时文本索引既可以支持其中某一个字段的查询,也可以支持所有字段的联合查询。

通配符

当在多个字段上创建文本索引时,你也可以使用通配符指定器($**)。使用通配符文本索引,MongoDB会对集合中每个文档中包含字符串数据的每个字段进行索引。下面的例子使用通配符指定器创建了一个文本索引:
db.collection.createIndex( { "$**": "text" } )

支持复合索引

文本索引支持在创建时使用复合索引,即在创建索引时同时文本索引和其他索引。

哈希索引(Hashed Indexes)

哈希索引使用一个哈希函数来计算索引字段的值的哈希。哈希函数对嵌入文档进行折叠并计算整个值的哈希值,但不支持多键(即数组)索引。具体来说,在包含数组的字段上创建哈希索引,或者试图将数组插入哈希索引字段中,都会返回错误。
当使用哈希索引时,MongoDB会自动计算哈希值,不需要手动处理。

创建哈希索引

创建哈希索引时只需要将索引键的值设为hashed 即可 。
db.collection.createIndex( { _id: "hashed" } )

集群索引(Clustered Indexes)

从MongoDB 5.3开始,您可以创建一个具有聚集索引的集合。使用聚集索引创建的集合称为聚集集合。

索引属性

唯一索引(Unique Indexes)

唯一索引可以确保索引字段唯一性,避免产生重复。

部分索引(Partial Indexes)

部分索引只对符合指定筛选条件的文档进行索引。

稀疏索引

稀疏索引不会对没有索引字段的文档进行索引。

TTL Indexes

TTL索引是特殊的索引,MongoDB可以用来在一定时间后自动从一个集合中删除文档。这对于某些类型的信息来说是非常理想的,比如机器生成的事件数据、日志和会话信息,它们只需要在有限的时间内持续存在于数据库。

Hidden Indexes

隐藏索引对查询计划程序不可见。
 

Case Insensitive Indexes

Case Insensitive索引会忽略索引键值的大小写。

参考