在优化数据库时,可用使用命令 db.system.profile.find()
来找出哪些语句执行速度慢,接下来通常会加一些索引来加速查询,那么增加的索引对于执行语句是否起了作用,就需要使用查看下详细的查询计划来验证并根据情况修改索引或其他的设置。
那么读懂详细的查询计划就是一个比较关键了。
explain输出结果说明
在执行类似于 db.collections.find().explain()
时只会输出(返回)
queryPlanner
与
serverInfo
而在执行类似于 db.collections.find().explain("executionStats")
时则会输出(返回)
queryPlanner
与
executionStats
与
serverInfo
queryPlanner
queryPlanner模式下并不会去真正进行query语句查询,而是针对query语句进行执行计划分析并选出winning plan。
非sharded的集合explain信息
在非分片的集合中,explain会返回如下格式的信息
{
"queryPlanner" : {
"plannerVersion" : <int>,
"namespace" : <string>,
"indexFilterSet" : <boolean>,
"parsedQuery" : {
...
},
"winningPlan" : {
"stage" : <STAGE1>,
...
"inputStage" : {
"stage" : <STAGE2>,
...
"inputStage" : {
...
}
}
},
"rejectedPlans" : [
<candidate plan 1>,
...
]
}
- namespace:该值返回的是该query所查询的表
- indexfilter:是否使用了索引过滤(index filter)
- winningPlan:查询优化器针对该query所返回的最优执行计划的详细内容
- winningPlan.stage:最优执行计划的stage
- winningPlan.inputStage:explain.queryPlanner.winningPlan.stage的child stage
- winningPlan.inputStage.keyPattern:所扫描的index内容,此处是w:1与n:1
- winningPlan.inputStage.indexName:winning plan所选用的index
- winningPlan.inputStage.isMultiKey:是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true
- winningPlan.inputStage.direction:此query的查询顺序,此处是forward,如果用了.sort({w:-1})将显示backward
- winningPlan.inputStage.indexBounds:winningplan所扫描的索引范围。
- rejectedPlans:其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同,故不在此赘述。
sharded的集合返回信息
{
"queryPlanner" : {
...
"winningPlan" : {
...
"shards" : [
{
"shardName" : <shard>,
<queryPlanner information for shard>,
<serverInfo for shard>
},
...
],
},
},
"executionStats" : {
...
"executionStages" : {
...
"shards" : [
{
"shardName" : <shard>,
<executionStats for shard>
},
...
]
},
"allPlansExecution" : [
{
"shardName" : <string>,
"allPlans" : [ ... ]
},
...
]
}
}
- explain.queryPlanner.winningPlan.shards:每个Shard上返回的queryPlanner和serverInfo信息
explain.executionStats.executionStages.shards :每个Shard上返回的executionStats 信息
Stage 分类
- 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的返回
executionStats
一般返回的executionStats信息如下
"executionStats" : {
"executionSuccess" : <boolean>,
"nReturned" : <int>,
"executionTimeMillis" : <int>,
"totalKeysExamined" : <int>,
"totalDocsExamined" : <int>,
"executionStages" : {
"stage" : <STAGE1>
"nReturned" : <int>,
"executionTimeMillisEstimate" : <int>,
"works" : <int>,
"advanced" : <int>,
"needTime" : <int>,
"needYield" : <int>,
"isEOF" : <boolean>,
...
"inputStage" : {
"stage" : <STAGE2>,
...
"nReturned" : <int>,
"executionTimeMillisEstimate" : <int>,
"keysExamined" : <int>,
"docsExamined" : <int>,
...
"inputStage" : {
...
}
}
},
"allPlansExecution" : [
{ <partial executionStats1> },
{ <partial executionStats2> },
...
]
}
- executionSuccess:是否执行成功
- nReturned:查询的返回条数
- executionTimeMillis:整体执行时间
- totalKeysExamined:扫描索引条目的数量
- totalDocsExamined:扫描文档的数量
- executionStages.nReturned:意义与nReturned一样
- executionStages.executionTimeMillisEstimate:意义与executionTimeMillis一样
- executionStages.docsExamined:意义与totalDocsExamined一样
- executionStages.executionStats.inputStage中:的与上述理解方式相同
executionTimeMillis 说明
executionStats.executionTimeMillis:指的是语句的执行整体时间
executionStats.executionStages.executionTimeMillis:该查询根据index去检索document获取nReturned条具体数据的时间
executionStats.executionStages.inputStage.executionTimeMillis:该查询扫描totalKeysExamined行index所用时间
executionTimeMillis 的理想状态
nReturned=totalKeysExamined & totalDocsExamined=0
这表示:仅仅使用到了index,无需文档扫描,这是最理想状态
或者
nReturned=totalKeysExamined=totalDocsExamined(需要具体情况具体分析)
这表示:正常index利用,无多余index扫描与文档扫描。)
如果有sort的时候,为了使得sort不在内存中进行,我们可以在保证nReturned=totalDocsExamined的基础上,totalKeysExamined可以大于totalDocsExamined与nReturned,因为量级较大的时候内存排序非常消耗性能。
Stage状态分析
Stage的类型会影响到totalKeysExamined与totalDocsExamined
- 对于普通查询希望的结果
Fetch+IDHACK
Fetch+ixscan
Limit+(Fetch+ixscan)
PROJECTION+ixscan
SHARDING_FILTER+ixscan
不希望看到包含如下的stage
COLLSCAN(全表扫),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index的$or)
对于count查询
希望看到COUNT_SCAN,而不是COUNT