我的专栏地址:我的 segmentfault, 欢迎浏览
一、执行计划介绍
MongoDB 3.0 之后,explain 的返回与使用方法与之前版本有了不少变化,介于 3.0 之后的优秀特色,本文仅针对 MongoDB 3.0+ 的 explain 进行讨论。现版本 explain 有三种模式,分别如下:
queryPlanner
executionStats
allPlansExecution
其中 queryPlanner 是现版本 explain 的默认模式,queryPlanner 模式下并不会去真正进行 query 语句查询,而是针对 query 语句进行执行计划分析并选出 winning plan。
举个执行计划的命令例子:
db.usertable.find({“w”: 1}).explain(“queryPlanner”)
举个执行计划响应结果的例子:
{
“queryPlanner”:{
“plannerVersion”:1,
“namespace”:”game_db.game_user”, #该值返回的是该 query 所查询的表
“indexFilterSet”:false, #是否应用了 index filter
“parsedQuery”:{#查询条件
“w”:{
“$eq”:1
}
},
“winningPlan”:{#查询优化器针对该 query 所返回的最优执行计划的详细内容
“stage”:”FETCH”, #最优执行计划的 stage,这里返回是 FETCH,可以理解为通过返回的 index 位置去检索具体的文档
“inputStage”:{# #explain.queryPlanner.winningPlan.stage 的 child stage,此处是 IXSCAN,表示进行的是 index scanning。
“stage”:”IXSCAN”, #索引查找
“keyPattern”:{#所扫描的 index 内容,此处是 w:1 与 n:1。
“w”:1,
“n”:1
},
“indexName”:”w_1_n_1″, #winning plan 所选用的 index。
“isMultiKey”:false, #本次查询是否使用了多键、复合索引
“direction”:”forward”, #此 query 的查询顺序,此处是 forward,如果用了.sort({w:-1})将显示 backward。
“indexBounds”:{#winningplan 所扫描的索引范围,此处查询条件是 w:1, 使用的 index 是 w 与 n 的联合索引,故 w 是 [1.0,1.0] 而 n 没有指定在查询条件中,故是[MinKey,MaxKey]。
“w”:[
“[1.0, 1.0]”
],
“n”:[
“[MinKey, MaxKey]”
]
}
}
},
“rejectedPlans”:[#其他执行计划(非最优而被查询优化器 reject 的)的详细返回,其中具体信息与 winningPlan 的返回中意义相同,故不在此赘述。
{
“stage”:”FETCH”,
“inputStage”:{
“stage”:”IXSCAN”,
“keyPattern”:{
“w”:1,
“v”:1
},
“indexName”:”w_1_v_1″,
“isMultiKey”:false,
“direction”:”forward”,
“indexBounds”:{
“w”:[
“[1.0, 1.0]”
],
“v”:[
“[MinKey, MaxKey]”
]
}
}
}
]
},
“serverInfo” : {
“host” : “ALI-SZ-VT-TEST001”,
“port” : 27017,
“version” : “4.0.5”,
“gitVersion” : “3739429dd92b92d1b0ab120911a23d50bf03c412”
},
“ok” : 1
}
二、queryPlanner 学习
2.1 Stage 的意义
如 explain.queryPlanner.winningPlan.stageexplain.queryPlanner.winningPlan.inputStage** 等。
stage/inputStage 值
值的意义
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 的返回
2.2 一个 stage/inputStage 的特点
执行一:
db.usertable.find({“field0”: “use”}).explain(“queryPlanner”)
{
…
“winningPlan” : {
“stage” : “COLLSCAN”,
“filter” : {
“field0” : {
“$eq” : “use”
}
},
“direction” : “forward”
},
…
}
执行二:
db.usertable.find({“field0”: “use”}).limit(1).explain(“queryPlanner”)
{
…
“winningPlan” : {
“stage” : “LIMIT”,
“limitAmount” : 1,
“inputStage” : {
“stage” : “COLLSCAN”,
“filter” : {
“field0” : {
“$eq” : “use”
}
},
“direction” : “forward”
}
},
…
}
执行二在执行一的基础上增加了 limit 限掉,queryPlanner 由 stage(COLLSCAN) 变成了 stage(LIMIT)、inputStage.stage(COLLSCAN)。说明在判断 queryPlanner 是否达到用户想要的效果要对 stageinputStage.stag 综合考虑。
参考文章:
MongoDB 干货系列 2 -MongoDB 执行计划分析详解 http://www.mongoing.com/eshu_explain2 官方文档:https://docs.mongodb.com/manual/tutorial/analyze-query-plan/