QuerySolution 执行计划(过滤条件filter、sort排序等都属于计划的一部分)
QueryPlaner 生成执行计划模块(explain()生成执行计划,不实际执行)
PlanExecutor 运行执行计划模块,同时充当优化器(Optimizer)的角色(explain(executionStats)实际运行执行计划)
- 1). Client按照MongoDB的网络协议,请求建立连接,并友单独新建的thread处理所有请求。
- 2). 有些Query(如insert),本身不需要执行计划和优化,这直接通过接口和引擎交互(通过RecordStore写表)
- 3). Query会进行简单的处理(标准化),并构造一些上下文数据结构变成CanonicalQuery(标准化Query)。
- 4). Plan模块会负责生成该Query的多个执行计划,然后丢给Optimizer去选择最优的,丢给PlanExecutor。
- 5). PlanExecutor按照执行计划一步一步迭代,获得最终的数据(或执行update修改数据)。
在此流程中: - Plan如果只关联到单个或零个索引,这只生成一个执行计划,如果发现有多个索引或者索引有重叠,这可能生成多个执行计划。
- Optimizer只在多个执行计划时,才会介入。
explain() 可以接收不同的参数,通过设置不同参数我们可以查看更详细的查询计划。
queryPlanner:是默认参数
explain() 设置参数的三种模式
1 queryPlanner
不会真正的执行查询,只是分析查询,选出winning plan。
2 executionStats
返回winning plan的关键数据。
executionTimeMillis该query查询的总体时间。
3 allPlansExecution
执行所有的plans。
> db.getCollection("stepsDetail").find( { "ssoid" : "670274649", "modifiedTime" : NumberLong(1619671871306) } ).explain()
{
"queryPlanner" : {
"mongosPlannerVersion" : 1,
"winningPlan" : {
"stage" : "SINGLE_SHARD",
"shards" : [
{
"shardName" : "sport-health_oXHqoVcC_shard_2", //分片
"connectionString" : "sport-health_oXHqoVcC_shard_2/10.177.233.79:20000,10.177.233.80:20000,10.177.233.81:20000",//链接字符串
"serverInfo" : { //MongoDB服务器信息
"host" : "10-177-233-81.mongodb-fatpod-sport-health.dgtest01",
"port" : 20000,
"version" : "3.6.13",
"gitVersion" : "db3c76679b7a3d9b443a0e1b3e45ed02b88c539f"
},
"plannerVersion" : 1, //查询计划版本
"namespace" : "sporthealth.stepsDetail", //要查询的集合
"indexFilterSet" : false, //boolean 查询模型是否使用索引过滤
"parsedQuery" : {//查询条件
"$and" : [
{
"modifiedTime" : {
"$eq" : NumberLong("1619671871306")
}
},
{
"ssoid" : {
"$eq" : "670274649"
}
}
]
},
"winningPlan" : { //最佳执行计划
"stage" : "FETCH",//最优执行计划的stage
"inputStage" : {
"stage" : "IXSCAN",//查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询
"keyPattern" : {//所扫描的index内容
"ssoid" : 1,
"modifiedTime" : -1
},
"indexName" : "ssoid_1_modifiedTime_-1",//winning plan所选用的index
"isMultiKey" : false,//是否是Multikey,此处返回是false,如果索引建立在array上,此处将是true。
"multiKeyPaths" : {
"ssoid" : [ ],
"modifiedTime" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",//此query的查询顺序,此处是forward,如果用了.sort({ssoid:-1})将显示backward。
"indexBounds" : {//winningplan所扫描的索引范围
"ssoid" : [
"[\"670274649\", \"670274649\"]"
],
"modifiedTime" : [
"[1619671871306, 1619671871306]"
]
}
}
},
"rejectedPlans" : [//其他执行计划(非最优而被查询优化器reject的)的详细返回,其中具体信息与winningPlan的返回中意义相同
{
"stage" : "FETCH",
"filter" : {//过滤条件
"$and" : [
{
"ssoid" : {
"$eq" : "670274649"
}
},
{
"modifiedTime" : {
"$eq" : NumberLong("1619671871306")
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {//所扫描的index内容
"ssoid" : "hashed"
},
"indexName" : "ssoid_hashed",//所选用的index
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"ssoid" : [
"[-6533328432691190449, -6533328432691190449]"
]
}
}
},
{
"stage" : "FETCH",
"filter" : { //过滤条件
"modifiedTime" : {
"$eq" : NumberLong("1619671871306")
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : { //所扫描的index内容
"ssoid" : 1,
"clientDataId" : 1
},
"indexName" : "ssoid_1_clientDataId_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"ssoid" : [ ],
"clientDataId" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"ssoid" : [
"[\"670274649\", \"670274649\"]"
],
"clientDataId" : [
"[MinKey, MaxKey]"
]
}
}
}
]
}
]
}
},
"ok" : 1, //操作状态
"operationTime" : Timestamp(1619683463, 3),////操作时间
"$clusterTime" : {
"clusterTime" : Timestamp(1619683468, 1),
"signature" : {
"hash" : BinData(0,"uCHZd6sSRBNKDLXw1xUi2mHErmo="),
"keyId" : NumberLong("6915417759157321730")
}
}
}
Stage状态分析
COLLSCAN 全表扫描
IXSCAN 扫描索引
FETCH 根据索引去检索指定document
SHARD_MERGE 将各个分片返回数据进行merge
SORT 表明在内存中进行了排序
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的返回
> db.getCollection("stepsDetail").find({"ssoid" : "670274649","modifiedTime" : NumberLong(1619671871306) } ).explain("executionStats")
"executionStats" : {
"nReturned" : 27,//查询的返回条数
"executionTimeMillis" : 1,//整体执行时间
"totalKeysExamined" : 27,//索引扫描次数
"totalDocsExamined" : 27,//document扫描次数
"executionStages" : {
"stage" : "SINGLE_SHARD",
"nReturned" : 27,//返回27条数据
"executionTimeMillis" : 1,//该查询根据index去检索document获取27条具体数据的时间
"totalKeysExamined" : 27,//索引扫描次数
"totalDocsExamined" : 27,//document扫描次数
"totalChildMillis" : NumberLong(1),
"shards" : [
{
"shardName" : "sport-health_oXHqoVcC_shard_2",
"executionSuccess" : true,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 27,
"executionTimeMillisEstimate" : 0,
"works" : 29,
"advanced" : 27,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 27,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN", //扫描方式
"nReturned" : 27, //查询结果数量
"executionTimeMillisEstimate" : 0, //预估耗时
"works" : 28, //工作单元数,一个查询会分解成小的工作单元
"advanced" : 27, //优先返回的结果数
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : { //索引
"ssoid" : 1,
"modifiedTime" : -1
},
"indexName" : "ssoid_1_modifiedTime_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"ssoid" : [ ],
"modifiedTime" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"ssoid" : [
"[\"670274649\", \"670274649\"]"
],
"modifiedTime" : [
"[1619671871306, 1619671871306]"
]
},
"keysExamined" : 27,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
]
}
}