关于mongodb索引 explain()函数的测试
dbtest表数据结构 : {a:“1”,b:“1”,c:“1”,d:“1”,e:“1”},
dbtest表:
索引1:abcde ,
查询条件:abc 执行索引1,
查询条件:ac 执行索引1,
查询条件:ace 执行索引1,
查询条件:aeb 执行索引1,
查询条件:bc 不执行索引1,
查询条件:dbc 不执行索引1,
查询条件:kbc 不执行索引1, k不存在索引键,
单索引.按查询条件的首键,必须是索引键的首键才能执行索引,并且查询条件内更多字段与单索引的键的排序匹配,查询效率更高
dbtest表:
索引1:abcde
索引2:bcd
查询条件:bc 执行索引1,
查询条件:dba 执行索引2, 拒绝执行索引1
查询条件:dbc 执行索引2,
查询条件:dbe 执行索引2,
查询条件:kbce 执行索引2, k不存在索引键,
查询条件:kdbe 执行索引2, k不存在索引键,
查询条件:kbe 执行索引2, k不存在索引键,
查询条件:kae 执行索引1, k不存在索引键,
双索引时,可不按查询条件与条件的索引顺序进行排序,但未能保证查询效率最优
dbtest表:
索引1:cd
索引2:abe,
查询条件:cd 执行索引1,
查询条件:bc 执行索引1, 索引2的b不是索引首键,无法匹配
查询条件:ca 执行索引1, 拒绝执行索引2
查询条件:ac 执行索引2,
dbtest表:
索引1:cd
索引2:abe,
索引3:ac,
查询条件:ca 执行索引1, 拒绝执行索引2和索引3
查询条件:ac 执行索引1, 拒绝执行索引2和索引3
dbtest表数据结构 : {a:"1",b:"1",c:"1",d:"1",e:"1"},
索引1:cd
索引2:abe,
索引3:ac,
查询语句: db.getCollection("dbtest").find({a:"1",c:"1"}).explain()
判断是否有启用索引: winningPlan.inputStage.IXSCAN 可选项:COLLSCAN 没有走索引;IXSCAN使用了索引) , rejectedPlans(候选的执行计划) executionStats(执行情况描述)
winningPlan.inputStage.indexBounds 查询优化器针对该查询所返回的最优执行计划的详细内容 {"a":["[\"1\", \"1\"]"],"b":["[MinKey, MaxKey]"]} , "[\"1\", \"1\"]",是根据查询条件传的值进行提示, MinKey是查询条件该索引用不到这个建
rejectedPlans.inputStage.indexBounds 其他执行计划(非最优而被查询优化器拒绝的)
利用mongodb 4.0数据库版本, 测试索引时,返回的结果,与3.x版本还有点差异,但下面的链接可以参考
{
"queryPlanner" : { // (执行计划描述) 是默认值,表示仅仅展示执行计划信息;
"plannerVersion" : 1.0,
"namespace" : "1004.dbtest",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [{"a":{"$eq":"1"}},{"c":{"$eq":"1"}}]
},
"winningPlan" : { //查询优化器针对该查询所返回的最优执行计划的详细内容
"stage" : "FETCH",
"filter" : {"a":{"$eq":"1"}},
"inputStage" : {
"stage" : "IXSCAN", //(可选项:COLLSCAN 没有走索引;IXSCAN使用了索引) rejectedPlans(候选的执行计划) executionStats(执行情况描述)
"keyPattern" : {"c":1.0,"d":1.0},
"indexName" : "c_1_d_1",
"isMultiKey" : false,
"multiKeyPaths" : {"c":[],"d":[]},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2.0,
"direction" : "forward",
"indexBounds" : {"c":["[\"1\", \"1\"]"],"d":["[MinKey, MaxKey]"]}
}
},
"rejectedPlans" : [ // 其他执行计划(非最优而被查询优化器拒绝的)
{
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN", //(可选项:COLLSCAN 没有走索引;IXSCAN使用了索引) rejectedPlans(候选的执行计划) executionStats(执行情况描述)
"keyPattern" : {"a":1.0,"c":1.0},
"indexName" : "a_1_c_1",
"isMultiKey" : false,
"multiKeyPaths" : {"a":[],"c":[]},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2.0,
"direction" : "forward",
"indexBounds" : {"a":["[\"1\", \"1\"]"],"c":["[\"1\", \"1\"]"]}
}
},
{
"stage" : "FETCH",
"filter" : {"c":{"$eq":"1"}},
"inputStage" : {
"stage" : "IXSCAN", //(可选项:COLLSCAN 没有走索引;IXSCAN使用了索引) rejectedPlans(候选的执行计划) executionStats(执行情况描述)
"keyPattern" : {"a":1.0,"b":1.0,"e":1.0},
"indexName" : "a_1_b_1_e_1",
"isMultiKey" : false,
"multiKeyPaths" : {"a":[],"b":[],"e":[]},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2.0,
"direction" : "forward",
"indexBounds" : {"a":["[\"1\", \"1\"]"],"b":["[MinKey, MaxKey]"],"e":["[MinKey, MaxKey]"]}
}
}
]
},
"ok" : 1.0,
"operationTime" : Timestamp(1588144252, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1588144252, 1),
"signature" : {
"hash" : BinData(0, "7VNm3KvacDc03o4NGrBSLQvdsKY="),
"keyId" : NumberLong(6776055669654028289)
}
}
}
参考的链接
explain.queryPlanner.namespace 顾名思义,该值返回的是该query所查询的表。
explain.queryPlanner.indexFilterSet 针对该query是否有indexfilter(会在后文进行详细解释)。
explain.queryPlanner.winningPlan 查询优化器针对该query所返回的最优执行计划的详细内容。
explain.queryPlanner.winningPlan.stage 最优执行计划的stage,这里返回是FETCH,可以理解为通过返回的index位置去检索具体的文档
explain.queryPlanner.winningPlan.stage的child stage,此处是IXSCAN,表示进行的是index scanning。
explain.queryPlanner.winningPlan.keyPattern 所扫描的index内容,此处是w:1与n:1。
explain.queryPlanner.winningPlan.indexName winning plan所选用的index。
explain.queryPlanner.winningPlan.isMultiKey 是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。
explain.queryPlanner.winningPlan.direction 此query的查询顺序,此处是forward,如果用了.sort({w:-1})将显示backward。
explain.queryPlanner.winningPlan.indexBounds winningplan所扫描的索引范围,此处查询条件是w:1,使用的index是w与n的联合索引,故w是[1.0,1.0]而n没有指定在查询条件中,故是[MinKey,MaxKey]。
explain.queryPlanner.rejectedPlans 其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述。
COLLSCAN //全表扫描
IXSCAN //索引扫描
FETCH //根据索引去检索指定document
SHARD_MERGE //将各个分片返回数据进行merge
SORT //表明在内存中进行了排序(与老版本的scanAndOrder:true一致)
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的返回
对于普通查询 我们最希望看到的组合有以下这些 Fetch+IDHACK; Fetch+ixscan; Limit+(Fetch+ixscan); PROJECTION+ixscan; SHARDING_FILTER+ixscan; 不希望看到的有以下这些 COLLSCAN(全表扫); SORT(使用sort但是无index); 不合理的SKIP; SUBPLA(未用到index的$or);
对于count查询 我们希望看到的有:COUNT_SCAN;不希望看到的有:COUNTSCAN
所以,当查询覆盖精确匹配,范围查询与排序的时候,精确匹配字段,排序字段,范围查询字段,这样的索引排序会更为高效。