一 索引简介
1.1 简介
mongo索引跟关系型数据的索引概念一样,相当于书的目录,能够快速定位数据。像关系型数据库一样我们可以通过explain看执行计划,如下图所示:
nscanned 扫描的文档数,millis 消耗的时间(毫秒)。可以发现这个是全表扫描,在username上面创建索引:
db.users.ensureIndex({"username":1}) //如果创建索引比较耗时,打开另外一个窗口查看进度 db.currentOp()
再次执行同样的查询,可以发现nscanned变成了1,millis也变成了个位数。
1.2 复合索引
在多个键上建立的索引叫做复合索引
1.2.1 键的方向
{"age":1,"username":-1} age 升序,username降序 跟另外一个索引是同一个含义{“age”:-1,"username":1}
1.2.2 覆盖索引
如果要查询的字段就在索引里面,就叫做覆盖索引扫描,这样避免了根据索引锁定位的地址再去找文档
1.2.3 隐 式索引
如果建立了索引{“a”:1,"b":1,"c":1,"d":1}, 相当于同时建立了{"a":1}, {"a":1,"b":1},{“a”:1,"b":1,"c":1}索引
1.3 索引使用
1.3.1 精确字段放前面,范围字段放后面
如果要进行查询{"age":47,"username":{"$gt":"user4","$lt":"user8"}}, 那么建立索引age放前面,username放后面
1.4 索引对象和数组
1.4.1 嵌套文档索引
可以对嵌套字段建立索引,比如db.users.ensureIndex({"local.city":1})
1.4.2 数组索引
有一博客集合{"title":"I am a bird","content":"I think I am a bird,fly.....","comment":[{"date":"2017-08-01","content":"good"},{"date":"2017-08-02","content":"shit"}]};
comment评论是一个数组,可以再数组的元素 上建立索引 db.blogs.ensureIndex({"comment.date":1}), 这个时候,多少条评论,就有多少个索引条目,比单索引代价要高很多。
1.5 使用explain()和hint()
查看执行计划使用explain,
1. cursor: BtreeCursor age_l_username_l
BtreeCursor表示使用了索引,后面是具体索引名称
2. isMultiKey: false
本次查询是否使用了多键索引
3. n: 8332
本次查询返回的文档数量
4. nscannedObjects: 8332
按照索引去磁盘查找实际文档次数,也就是索引的内容不足以返回给用户,还需要去查找具体内容
5. nscaned: 8332
查找过的索引条目数(索引扫描),检查过的文档数(全表扫描)
6. scanAndOrder: false
是否在内存中对结果进行排序
7. indexOnly: false
是否只使用索引就完成了本次查询
8. nYields: 0
为了让写入顺利进行,本次查询被暂停次数
9. millis: 91
查询耗费的毫秒数
10. indexBounds:
索引的使用情况
1.6 查询优化器
mongodb的查询优化器与其他的数据有不同,如果一个查询是精确查询(要查询x,而x上刚好有索引),那么查询优化器就会使用索引。否则可能有好几个索引适合你的查询。mongbo不会去评估哪一个索引比较合适,而是所有的索引都生成一个执行计划,一起执行。最早返回100个结果的为胜利者。然后将最早的这个胜利者缓存起来,后续再执行的时候,就使用这个胜利者了。(如果数据发生大变动,胜利者可能也不是最优的了,建立索引,或者每执行1000次查询的时候,重新评估胜利者)
1.7 何时不应该使用索引
如果返回的数据量占比大于总数据量30%,不适合用索引。 如果发现使用了索引,可以强制全表扫描:
db.entries.find({"create_at":{"$lt":hourAgo}}).hint({"$natrual":1}); //natrual强制走全表扫描
1.8 索引类型
1.8.1 唯一索引
db.user.ensureIndex({"username":1},{"unique":true})
保证唯一性,但是索引是有大小的,字段不能大于1024字节,如果大于的话,这个文档不会被索引。
1.8.2 稀疏索引
如果有一个可能存在,也可能不存在的字段。当存在时候,必须唯一,就需要建立稀疏索引
db.user.ensureIndex({"email":1},{"unique":true, "sparse":true})
如果去掉unique,就是非唯一稀疏索引
注意使用索引的时候,如果字段为空,也会被存储在索引里面。查询的时候,可能会查询不到,需要注意。