索引一般用来提高查询效率,避免全集合搜索,那么在mongodb中,支持索引么?如果支持,如何定义索引,如何使用索引,如何确定一个sql是否走索引?
1. 创建索引
语法定义:
1 | db.collection.createIndex(keys, options) |
请注意,在3.0之前的版本中,也可以使用ensureIndex
来创建索引
参数说明:
- keys:kv结构,key为fieldName, value为1 表示升序创建索引;-1 表示降序创建索引;支持多字段索引
- options:可选参数
常见参数说明如下表:
参数名 | 说明 |
---|---|
background |
true,则后台方式创建索引,不阻塞其他操作;默认为false |
unique |
true,则表示唯一约束索引,比如_id 就有唯一约束;默认为false |
name |
索引名,不指定时,根据field + 方向生成索引名 |
sparse |
true, 则不包含这个字段的不创建索引,且索引查询时查不到不包含这个字段的文档;默认false |
expireAfterSeconds |
设置文档在集合的生存时间,s为单位 |
v |
版本号 |
weight |
索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重 |
default_language |
对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override |
对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language |
实例如下:
1 | db.doc_demo.createIndex({'name': 1}, {'background': true}) |
2. 索引查询
查看一个集合定义了哪些索引,借助getIndexes()
方法即可,如
1 | db.doc_demo.getIndexes() |
3. 索引分析
虽然我们创建了索引,但是我们的查询语句却并不一定会走索引,在mysql中我们知道有一个explain
语句来分析索引情况,在mongodb中也存在类似的方法
集合数据如下
1 | { "_id" : ObjectId("5e7b5ac10172dc950171c488"), "name" : "一灰灰blog", "age" : 19, "skill" : [ "java", "python", "sql" ], "tag" : 2 } |
当前集合上除了默认的_id
索引之外,针对name
也创建了升序索引
如需要判断一个查询语句的情况,可以在后面加上explain()
方法,如下
1 | db.doc_demo.find({'name': '一灰灰'}).explain() |
输出如下
1 | { |
关于是否走索引,主要看stage,通常会有以下几种状态
stage | 描述 |
---|---|
COLLSCAN | 全表扫描 |
IXSCAN | 扫描索引 |
FETCH | 根据索引去检索指定document |
SHARD_MERGE | 将各个分片返回数据进行merge |
SORT | 表明在内存中进行了排序 |
LIMIT | 使用limit限制返回数 |
SKIP | 使用skip进行跳过 |
IDHACK | 针对_id进行查询 |
SHARDING_FILTER | 通过mongos对分片数据进行查询 |
COUNT | 利用db.coll.explain().count()之类进行count运算 |
COUNTSCAN | count不使用Index进行count时的stage返回 |
COUNT_SCAN | count使用了Index进行count时的stage返回 |
SUBPLA | 未使用到索引的$or查询的stage返回 |
TEXT | 使用全文索引进行查询时候的stage返回 |
PROJECTION | 限定返回字段时候stage的返回 |
上面的具体查询,对应的stage组合是Fetch+ixscan
,也就是说会根据索引查询
虽然mongodb会根据查询来选择索引,但并不能保证都能选到最优的索引;这种时候我们可以通过hint
来强制指定索引,举例如下
1 | db.doc_demo.find({'age': 18, 'name':'一灰灰'}).hint({'name': 1}).explain() |
4. 删除索引
一般有下面两种删除方式,全量删除和指定索引删除
1 | # 全量删除 |
请注意,指定索引名删除时,如果不确定索引名是啥,可以通过getIndexes()
来查看
5. 文档自动删除
在创建索引的时候,其中有一个参数比较有意思,有必要单独拿出来说明一下,expireAfterSeconds
设置文档的生存时间
使用它有几个潜规则:
- 索引字段为Date类型
- 单字段索引,不支持混合索引
- 非立即执行
1 | # 插入一条文档,请注意这个时间,因为时区原因相对于北京时间,少8小时 |
然后过一段时间(并不一定10:55分的时候会删除)再去查询,会发现插入的文档被删除了
利用这种特性,在mongodb中存一些需要定时删除的数据,相比较我们常用的mysql而言,还是有很大优势的
6. 覆盖索引
覆盖索引的概念有些类似mysql中的不回表查询的case,直接查询索引,就可以返回所需要的字段了
比如在前面的case中,我只查询name字段,可以走覆盖索引;但是返回除了name,还有_id
,那么就不能了
1 | # 覆盖索引 |
注意:所有索引字段是一个数组时,不能使用覆盖索引
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
3. 扫描关注
一灰灰blog