1 索引概述
索引支持在 MongoDB 中高效地执行查询,避免 MongoDB 执行全集合扫描来选择与查询语句匹配的文档,这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询要花费几十秒甚至几分钟,严重影响网站的整体性能。如果查询存在适当的索引,MongoDB 可以使用该索引限制必须检查的文档数。
索引是特殊的数据结构,以易于遍历的形式存储集合数据集的一小部分,索引存储特定字段或一组字段的值,按字段值排序,索引项的排序支持有效的相等匹配和基于范围的查询操作,MongoDB 可以使用索引中的排序返回排序结果,MongoDB 索引使用 B 树数据结构。
2. 索引的类型
2.1 单字段索引
MongoDB 支持在文档的单个字段上创建自定义的升序/降序索引,称为单字段索引。对于单个字段索引和排序操作,索引键的排序顺序并不重要,因为 MongoDB 可以在任何方向上遍历索引。
2.2 复合索引
MongoDB 还支持多个字段的用户定义索引,即复合索引。复合索引中列出的字段顺序具有重要意义,例如,如果复合索引由{userid:1,score:-1}
组成,则索引首先按userid
正序排序,然后在每个userid
的值内,再按 score 倒序排序。
2.3 其他索引
(1) 地理空间索引:为了支持对地理空间坐标数据的有效查询,MongoDB 提供了两种特殊的索引,返回结果时使用平面几何的二维和返回结果时使用球面几何的三维球面索引。
(2) 文本索引:MongoDB 提供了一种文本索引类型,支持在集合中搜索字符串内容,这些文本索引不存储特定于语言的停止词,而将集合的词作为词干,只存储词根。
(3) 哈希索引:为了支持基于散列的分片,MongoDB 提供了散列索引类型,它对字段值的散列进行索引,这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。
3. 索引的管理操作
3.1 查看索引
语法格式如下:
db.collection.getIndexes()
例如,查看 comment 集合中所有的索引情况:
查询结果中显示的是 _id
索引,MongoDB 在创建集合的过程中,在 _id
字段上自动创建一个唯一的索引,默认为 _id
,该索引可以防止客户端插入两个具有相同值的文档,不能在_id
字段上删除索引。
3.2 创建索引
语法格式如下:
db.collection.createIndex(keys,options)
参数:
Parameter | Type | Description |
keys | document | 包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型,对于字段上的升序索引,指定值为1,对于降序索引,指定值为-1. 例如, {字段:1或-1} |
options | document | 可选,包含一组控制索引的创建的选项的文档 |
options 列表:
Parameter | Type | Description |
background | boolean | 建索引过程会阻塞其他数据库操作,background 可指定以后台方式创建索引,增加 background 可选参数,默认值为 false |
unique | boolean | 建立的索引是否唯一,指定为 true 创建唯一索引,默认值为 false |
name | string | 索引的名称,如果未指定,MongoDB 通过连接索引的字段名称和排序顺序生成一个索引名称 |
sparse | boolean | 对文档中不存在的字段数据不启用索引,默认值为 false,如果设置为 true 的话,在索引字段中不会查询查询出不包含对应字段的文档 |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL 设定,设定集合的生存时间 |
v | index version | 索引的版本号,默认的索引版本取决于 mongodb 创建索引时运行的版本 |
weights | document | 索引权重值,数值在1到99,999之间,表示该索引相对于其他索引字段的得分权重 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表,默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认值为 language |
(1) 单字段索引,对 userid
字段建立升序索引:
db.comment.createIndex({userid:1})
(2) 复合索引,对 userid
和 nickname
两个字段建立复合索引:
db.comment.createIndex({userid:1, nickname:-1}) • 1
3.3 删除索引
语法格式如下:
db.collection.dropIndex(index) • 1
参数:
Parameter | Type | Description |
index | string or document | 指定要删除的索引,可以通过索引名称或索引规范文档指定索引,如果删除文本索引,需要指定索引名称 |
例如,删除 comment 集合中 userid
字段的升序索引:
db.comment.dropIndex({userid:1})
如果需要一次性删除所有索引,语法格式如下:
db.collection.dropIndexes()
例如,删除 comment 集合中的所有索引(除 _id 索引外):
db.comment.dropIndexes()
4. 索引的使用
4.1 执行计划
分析查询性能通常使用执行计划来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
语法格式如下:
db.collection.find(query,options).explain(options)
查看根据 userid
查询数据的情况:
>db.comment.find({userid:"1003"}).explain() { queryPlanner: { plannerVersion: 1, namespace: 'article.comment', indexFilterSet: false, parsedQuery: { userid: { '$eq': '1003' } }, winningPlan: { stage: 'FETCH', inputStage: { stage: 'IXSCAN', keyPattern: { userid: 1 }, indexName: 'userid_1', isMultiKey: false, multiKeyPaths: { userid: [] }, isUnique: false, isSparse: false, isPartial: false, indexVersion: 2, direction: 'forward', indexBounds: { userid: [ '["1003", "1003"]' ] } } }, rejectedPlans: [] }, serverInfo: { host: 'VM-4-5-centos', port: 27017, version: '4.2.15', gitVersion: 'd7fd78dead621a539c20791a93abec34bb1be385' }, ok: 1 }
其中,"stage": "IXSCAN"
表示基于索引的扫描。
4.2 覆盖的查询
当查询条件和查询的投影仅包含索引字段时,MongoDB 将直接从索引返回结果,而不扫描任何文档或将文档带入内存,这些覆盖的查询可以非常有效。
>db.comment.find({userid:"1003"},{userid:1,_id:0}) { userid: '1003' } { userid: '1003' } >db.comment.find({userid:"1003"},{userid:1,_id:0}).explain() { queryPlanner: { plannerVersion: 1, namespace: 'article.comment', indexFilterSet: false, parsedQuery: { userid: { '$eq': '1003' } }, winningPlan: { stage: 'PROJECTION_COVERED', transformBy: { userid: 1, _id: 0 }, inputStage: { stage: 'IXSCAN', keyPattern: { userid: 1 }, indexName: 'userid_1', isMultiKey: false, multiKeyPaths: { userid: [] }, isUnique: false, isSparse: false, isPartial: false, indexVersion: 2, direction: 'forward', indexBounds: { userid: [ '["1003", "1003"]' ] } } }, rejectedPlans: [] }, serverInfo: { host: 'VM-4-5-centos', port: 27017, version: '4.2.15', gitVersion: 'd7fd78dead621a539c20791a93abec34bb1be385' }, ok: 1 }