看完就懂的MongoDB索引命中分析流程

1,003 阅读2分钟

每个开发者,都避免不了CRUD,当你查询的数据量极大时,我们都需要考虑索引的命中情况,那么如何分析是否命中索引呢?

首先,Mongo的索引分析,必不离开explain关键方法,这是对我们查询语句的命中索引分析指令。而查询Mongo当前表的索引可以用getIndexes方法。

本文主要讲Mongo索引分析中的winningPlanrejectedPlans里的索引命中规则。

(1)执行explain索引分析后,对命中索引顺序的流程如下:

mongo索引命中顺序为:SHARDING_FILTER -> IXSCAN -> FETCH -> GROUP -> SHARD_MERGE -> COLLSCAN

stage名词分析说明:

  • COLLSCAN:它是全表扫描,没有命中索引。
  • IXSCAN:使用索引扫描,即命中到索引,并通过索引来获取需要的数据。
  • FETCH:根据条件,从磁盘中获取数据。
  • GROUP:聚合操作,将数据按照指定的条件进行分组。
  • SHARD_MERGE:进行分片合并,将分片中的数据进行合并。
  • SHARDING_FILTER:进行分片过滤,过滤掉不符合条件的数据。

根据名词结合执行顺序得出: 首先通过分片过滤来减少需要扫描的数据量,再使用索引扫描来获取需要的数据。当需要从磁盘中获取数据时,则使用'Fetch'操作,如果有聚合操作,则进行'GROUP'操作,当数据是分散到多个分片的话,则再进行'SHARD_MEGRE'合并分片操作。如果上面的操作都无法获取到需要的数据,则再进行最后的'COLLSCAN'全表扫描的操作

(2)winningPlanrejectedPlans的区别

当你执行explain()方法分析命中索引情况时,会在对象里看到两个属性winningPlanrejectedPlans。他们都代表命中索引的情况。

  1. winningPlan是Mongo根据条件进行选择最优的一个索引。
  2. rejectedPlans是命中的其他索引,只是它不是当前查询最优的索引。

rejectedPlans里面命中的索引在执行查询时,可能是比winningPlan更耗资源或者需要更多的IO操作。

(3)举个例子

下面的对TestCollection集合进行索引分析, 执行语句如下:

db.getCollection('TestCollection')
.find({IsDeleted: false, CreateUserId: 123456, AccountId: 123456})
.explain()

win-inputstage.png

分析一下执行后的结果,先看Mongo帮我们选择最优的索引是哪个。winningPlan下的inputStagestageIXSCAN进行了索引扫描后, keyPattern就是最优的索引。命中最优的索引是{AccountId: 1, ExternalId: 1}。命中后过滤后的数据再交给FETCH从磁盘里去获取数据。

FETCH会根据查询条件中去过滤这部分数据,过滤条件是filter字段里的条件,如下图:

win-stage.png