在第一篇的文章末尾我们提到了索引,下面就将从不同的索引类型,索引的机制展开来介绍MongoDb的索引应用。

  • 为什么需要索引
  • 单字段索引
  • 复合索引
  • 多Key索引
  • 文本索引
  • Hash索引
  • 索引的额外属性
  1. 当你抱怨MongoDb的查询效率低下的时候,可能你就需要考虑索引了,先科普MongoDb里面的索引机制,当你往MongoDb插入数据的时候,每个文档经过底层的存储引擎持久化数据,会生成一个位置信息,通过这个位置信息就能通过存储引擎读出该文档,在MMAP中 位置信息是「文件Id + 文件的Offset」;在WT存储引擎中(KV存储引擎),位置信息是WT在存储文档的时候生成一个Key,通过这个Key就能访问到文档,位置信息我们用Position来表示。




mongodb 底层是什么_字段


创建原始的数据

插入Document之后,生成的位置信息如下图:


mongodb 底层是什么_字段_02


假如现在查询年龄为10的所有文档,这时候需要遍历所有的Document【全表扫描】,根据位置信息读出年龄为10的文档,当然如果表里面的数据很少的话不会有什么性能问题,但是如果数据达到几百万,甚至过亿的时候,对集合的全表扫描开销是非常大的,一个查询可能耗费数十秒甚至几分钟都有可能。

如果想加速上面的查询,我们就需要对Age字段建立索引 ,db.persons.createIndex({age:1}) //对Age字段建立升序索引,建立索引之后,mongodb额外会存储一个升序排序的索引数据,索引通常采用B-Tree的结构持久化,以保证快速的从索引里面找到对应的Age位置信息(position),然后找出对应的Document。


mongodb 底层是什么_mongodb 底层是什么_03


通常来说,索引就是将文档按照某个字段顺序组织起来,以便能根据这个字段进行高效查询,有了索引能优化以下的场景:

  1. 查询年龄为10的所有文档
  2. 更新,删除年龄为10 的文档,查询和更新需要根据条件来找出所有符合的数据进行更新,本质上也是查询优化。
  3. 排序,按照年龄进行排序,如果没有索引,也会进行全表扫描,然后对扫描的结果进行排序
  4. 同时MongoDb会自动为默认的_id 字段增加索引

单字段索引

db.person.createindex({age:1}) 上述语句对age字段创建来索引,使其能加速对Age字段各种查询,这是一种最常见对索引,mongodb创建对默认索引_id,也是这样的,{age:1}代表升序索引 ,{age:-1}代表降序索引,对于单字段索引来说,升序和降序都是一样的效果

复合索引

复合索引是单字段索引的升级版本,它对多个字段联合创建索引,先按第一个字段排序,第一个字段相同的文档按照第二个字段排序,依次类推,如下我们创建一个Age,name复合索引

db.createIndex({age:1,name,:1});

上述索引对应的的数据组织如下图,先按照Age字段排序,然后在按照Name字段排序,


mongodb 底层是什么_升序_04


复合索引能满足比单字段索引更丰富单应用场景,不光能满足单个字段组合起来查询,同时还能满足所有前缀字段的查询,这里的 {age:1} 就是{age:1,name:1}索引的前缀,所以类似的db.persons.find({age:1}) 也会使用这个复合索引,但是 {name:1} 就不会使用这个索引,如果要经常根据Name字段来查询,应该创建{name:1,age:1}这样的索引查询name的时候进行了全表的扫描


mongodb 底层是什么_字段_05


对Age进行查询的时候则是使用了复合索引来查询的


mongodb 底层是什么_mongodb 底层是什么_06


多Key索引

当索引的字段为数组时,创建出来的索引为多Key索引,多Key索引会为数组的每个元素都创建一条索引,比如我们在persons表在增加一个habbit字段「数组」,需要查询由相同爱好的人,就可以利用多Key索引


mongodb 底层是什么_升序_07


Hash索引

哈希索引是按照某个字段的Hash值来建立索引的,目前主要应用于MongoDb Shard Cluster的Hash分片,并且Hash索引只能满足字段的完全匹配,不能满足范围查询。

地理位置索引(2d索引)

能很好解决020的应用场景,查找某一位置的附近区域

文本索引

主要用来解决快速文本的查找,例如博客的内容,如果按照博客的内容查找,就要建立文本索引,并且支持分词。


下面在介绍一下索引的一些特性

  1. 唯一索引:(unique index)保证索引的字段不会出现相同的值,例如_id就是唯一索引。
  2. TTL索引:可以针对某个时间字段,指定文档的过期时间。
  3. 部分索引:(partial index)只针对复合某个特定条件的文档来建立索引,并且3.2以后的版本才支持。
  4. 稀疏索引:(sparse index)只针对存在索引字段的文档建立索引,可以看作是部分索引的一种特殊的情况。

最后我们说一下,db profiling

  1. 0, 不开启Profilling
  2. 1,将处理时间都超过某个阀值的请求记录到system.profile集合
  3. 2,将所有的请求都记录到system.profile集合

在生产环境中我们建议使用1,来监视慢的请求,来做进一步的优化。