解释结果
在此页面上
为了返回查询计划和查询计划执行统计信息,MongoDB 提供:
cursor.explain()
方法,以及explain
命令。
explain
结果将查询计划显示为阶段树。
"winningPlan" : { "stage" : <STAGE1>, ... "inputStage" : { "stage" : <STAGE2>, ... "inputStage" : { "stage" : <STAGE3>, ... } } },
每个阶段都会传递其结果(即 文档或索引键)复制到父节点。 叶节点访问权限集合或索引。 内部节点操作由子节点产生的文档或索引键。 节点是MongoDB派生结果设立的最后阶段。
阶段是对操作的描述;例如
COLLSCAN
用于集合扫描IXSCAN
用于扫描索引键FETCH
用于检索文档SHARD_MERGE
用来合并来自分片的结果SHARDING_FILTER
用于从分片中筛掉孤儿文档
解释输出
以下部分列出了explain
操作返回的一些关键字段。
注意
该字段列表并非详尽无遗,而是旨在突出显示与早期版本的explain相比的一些关键字字段更改。
输出格式可能因版本而异。
queryPlanner
queryPlanner
信息详细说明了查询优化器选择的计划。
对于未分片的集合,explain
将返回以下 queryPlanner
信息:
"queryPlanner" : { "plannerVersion" : <int>, "namespace" : <string>, "indexFilterSet" : <boolean>, "parsedQuery" : { ... }, "queryHash" : <hexadecimal string>, "planCacheKey" : <hexadecimal string>, "optimizedPipeline" : <boolean>, // Starting in MongoDB 4.2, only appears if true "winningPlan" : { "stage" : <STAGE1>, ... "inputStage" : { "stage" : <STAGE2>, ... "inputStage" : { ... } } }, "rejectedPlans" : [ <candidate plan 1>, ... ] }
对于分片集合,explain
包括核心查询规划器和 shards
字段中每个被访问分片的服务器信息:
"queryPlanner" : { "mongosPlannerVersion" : <int>, "winningPlan" : { "stage" : <STAGE1>, "shards" : [ { "shardName" : <string>, "connectionString" : <string>, "serverInfo" : { "host" : <string>, "port" : <int>, "version" : <string>, "gitVersion" : <string> }, "plannerVersion" : <int>, "namespace" : <string>, "parsedQuery" : <document>, "queryHash" : <hexadecimal string>, "planCacheKey" : <hexadecimal string>, "optimizedPipeline" : <boolean>, // Starting in MongoDB 4.2, only appears if true "winningPlan" : { "stage" : <STAGE2>, "inputStage" : { "stage" : <STAGE3> ..., } }, rejectedPlans: [ <candidate plan1>, ] } ] } }
explain.queryPlanner
包含查询优化器所选查询计划的相关信息。
explain.queryPlanner.namespace
一个字符串,使用数据库的名称和查询访问的集合指定该命名空间。该命名空间的格式为
<database>.<collection>
。
explain.queryPlanner.queryHash
一个十六进制字符串,表示查询结构的哈希值,且仅取决于查询结构。
queryHash
有助于识别具有相同查询结构的慢查询(包括写入操作的查询筛选器)。注意
与任何哈希函数一样,两个不同的查询结构可能会产生相同的哈希值。但是,不同查询结构之间不太可能发生哈希冲突。
有关
queryHash
和planCacheKey
的更多信息,请参阅queryHash
和planCacheKey
。4.2 版本中的新增功能。
explain.queryPlanner.planCacheKey
与此查询关联的计划缓存条目的键的哈希值。
与
queryHash
不同,planCacheKey
是查询结构和该结构当前可用索引的函数。换言之,如果添加/删除可以支持该查询结构的索引,则planCacheKey
值可能会更改,而queryHash
值不会更改。有关
queryHash
和planCacheKey
的更多信息,请参阅queryHash
和planCacheKey
。4.2 版本中的新增功能。
explain.queryPlanner.optimizedPipeline
一个布尔值,表明整个聚合管道操作已被优化掉,改用查询计划执行阶段树来实现。
例如,以下聚合操作可以通过查询计划执行树来完成,而不使用聚合管道。
db.example.aggregate([ { $match: { someFlag: true } } ] ) 仅当值为
true
时,该字段才存在,并且仅适用于解释聚合管道操作。为true
时,由于管道已被优化掉,所以输出中不会出现聚合阶段信息。4.2 版本中的新增功能。
explain.queryPlanner.winningPlan
详细说明查询优化器所选计划的文档。 MongoDB将计划表示为阶段树;即一个阶段可以有一个
inputStage
,或者,如果该阶段有多个子阶段,则可以有一个inputStages
。
executionStats
返回的 executionStats
信息详细说明了获胜计划的执行情况。为了在结果中包含 executionStats
,您必须在如下位置运行解释:
allPlansExecution 冗余模式。使用
allPlansExecution
模式以包含计划选择过程中捕获的部分执行数据。
对于未分片的集合,explain
将返回以下 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>, "saveState" : <int>, "restoreState" : <int>, "isEOF" : <boolean>, ... "inputStage" : { "stage" : <STAGE2>, "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, ... "inputStage" : { ... } } }, "allPlansExecution" : [ { "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, "totalKeysExamined" : <int>, "totalDocsExamined" :<int>, "executionStages" : { "stage" : <STAGEA>, "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, ... "inputStage" : { "stage" : <STAGEB>, ... "inputStage" : { ... } } } }, ... ] }
对于分片集合,explain
包括每个访问的分片的执行统计信息。
"executionStats" : { "nReturned" : <int>, "executionTimeMillis" : <int>, "totalKeysExamined" : <int>, "totalDocsExamined" : <int>, "executionStages" : { "stage" : <STAGE1> "nReturned" : <int>, "executionTimeMillis" : <int>, "totalKeysExamined" : <int>, "totalDocsExamined" : <int>, "totalChildMillis" : <NumberLong>, "shards" : [ { "shardName" : <string>, "executionSuccess" : <boolean>, "executionStages" : { "stage" : <STAGE2>, "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, ... "chunkSkips" : <int>, "inputStage" : { "stage" : <STAGE3>, ... "inputStage" : { ... } } } }, ... ] } "allPlansExecution" : [ { "shardName" : <string>, "allPlans" : [ { "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, "totalKeysExamined" : <int>, "totalDocsExamined" :<int>, "executionStages" : { "stage" : <STAGEA>, "nReturned" : <int>, "executionTimeMillisEstimate" : <int>, ... "inputStage" : { "stage" : <STAGEB>, ... "inputStage" : { ... } } } }, ... ] }, { "shardName" : <string>, "allPlans" : [ ... ] }, ... ] }
explain.executionStats
包含描述入选计划的已完成查询执行的统计信息。对于写入操作,已完成的查询执行是指将要执行的修改,但不将这些修改应用到数据库。
explain.executionStats.nReturned
获胜查询计划返回的文档数。
nReturned
对应于早期版本的 MongoDB 中的cursor.explain()
返回的n
字段。
explain.executionStats.executionTimeMillis
选择查询计划和执行查询所需的总时间(以毫秒为单位)。它包括运行计划选择过程的试用阶段部分所需的时间,但不包括将数据传输回客户端的网络时间。
explain.executionStats.executionTimeMillis
报告的时间不一定代表实际查询时间。在稳定状态操作期间(缓存查询计划时),或者将cursor.hint()
与cursor.explain()
一起使用时,MongoDB 会绕过计划选择过程,从而缩短实际时间,从而导致explain.executionStats.executionTimeMillis
值更低。
explain.executionStats.totalKeysExamined
扫描的索引项数。
totalKeysExamined
对应于早期版本的 MongoDB 中的cursor.explain()
返回的nscanned
字段。
explain.executionStats.totalDocsExamined
查询执行过程中检查的文档数量。检查文档的常见查询执行阶段是
COLLSCAN
和FETCH
。注意
totalDocsExamined
是指已检查的文档总数,而非返回的文档数量。例如,阶段可以按照顺序检查文档以应用过滤器。如果文档被过滤掉,则说明它已被检查过,但不会纳入查询结果集返回。如果在查询执行过程中多次检查了一个文档,
totalDocsExamined
会对每次检查进行计数。也就是说,totalDocsExamined
不是所检查的唯一文档的总数。
explain.executionStats.executionStages
以阶段树的形式详细说明获胜计划的执行情况;即一个阶段可以有一个
inputStage
或多个inputStages
。每个阶段都包含针对该阶段的执行信息。
explain.executionStats.executionStages.works
指定查询执行阶段执行的“工作单元”数量。查询执行将其工作划分为多个小单元。“工作单元”可能包括检查单个索引键、从集合中获取单个文档、将投影应用于单个文档或进行内部簿记。
explain.executionStats.executionStages.needTime
未将中间结果推进到其父阶段的工作周期数(请参阅
explain.executionStats.executionStages.advanced
)。 例如,索引扫描阶段可能会花费一个工作周期来寻找索引中的新位置,而不是返回索引键;此工作周期将计入explain.executionStats.executionStages.needTime
而不是explain.executionStats.executionStages.advanced
。
explain.executionStats.executionStages.isEOF
指定执行阶段是否已到达流结束:
如果为
true
或1
,则执行阶段已到达流结束。如果为
false
或0
,则该阶段可能仍有结果要返回。考虑一个具有限制的查询,其执行阶段由LIMIT
个阶段组成,输入阶段为IXSCAN
。如果查询返回的结果超过指定的限制,则LIMIT
阶段将报告isEOF: 1
,但其底层的IXSCAN
阶段将报告isEOF: 0
。
explain.executionStats.executionStages.inputStage.keysExamined
对于扫描索引的查询执行阶段(例如 IXSCAN),
keysExamined
是索引扫描过程中检查的界内和界外键的总数。 如果索引扫描由单个连续范围的键组成,则仅需要检查界内键。 如果索引边界由多个键范围组成,则索引扫描执行过程可能会检查越界键,以便从一个范围的末尾跳到下一个范围的开头。考虑以下示例,其中存在字段
x
的索引,并且集合包含100个文档,其x
值为1到100 :db.keys.find( { x : { $in : [ 3, 4, 50, 74, 75, 90 ] } } ).explain( "executionStats" ) 查询将扫描键
3
和4
。 然后,它将扫描键5
,检测到其越界,并跳到下一个键50
。继续此过程,查询会扫描键3 、 4 、 5 、 50 、 51 、 74 、 75 、 76 、 90和91 。 键
5
、51
、76
和91
是仍在检查中的界外键。keysExamined
的值为10 。
explain.executionStats.allPlansExecution
包含在计划选择阶段为中标和被拒计划捕获的部分执行信息。该字段仅在
explain
以allPlansExecution
详细模式运行时出现。
具有 管道阶段的查询的执行计划统计信息$lookup
版本 5.0 中的新增功能。
解释结果可包括使用 $lookup
管道阶段的查询的执行统计数据。要包含这些执行统计信息,您必须在以下执行详细模式运行解释操作:
以下字段包含在 $lookup
查询的解释结果中:
'$lookup': { from: <string>, as: <string>, localField: <string>, foreignField: <string> }, totalDocsExamined: <long>, totalKeysExamined: <long>, collectionScans: <long>, indexesUsed: [ <string_1>, <string_2>, ..., <string_n> ], executionTimeMillisEstimate: <long>
要查看 $lookup
部分中字段的说明,请参阅 $lookup
页面。
其他字段为:
serverInfo
对于未分片集合, explain
返回 MongoDB 实例的以下 serverInfo
信息:
"serverInfo" : { "host" : <string>, "port" : <int>, "version" : <string>, "gitVersion" : <string> }
对于分片集合, explain
返回每个所访问分片的 serverInfo
,并返回 mongos
的顶级 serverInfo
对象。
"queryPlanner" : { ... "winningPlan" : { "stage" : <STAGE1>, "shards" : [ { "shardName" : <string>, "connectionString" : <string>, "serverInfo" : { "host" : <string>, "port" : <int>, "version" : <string>, "gitVersion" : <string> }, ... } ... ] } }, "serverInfo" : { // serverInfo for mongos "host" : <string>, "port" : <int>, "version" : <string>, "gitVersion" : <string> } ...
3.0格式更改
从 MongoDB 3.0开始, explain
结果的格式和字段与以前的版本相比已发生变化。 下面列出了一些主要区别。
集合扫描与索引使用
如果查询规划器选择集合扫描,解释结果将包含 COLLSCAN
阶段。
如果查询规划器选择索引,解释结果将包含 IXSCAN
阶段。该阶段包括索引键模式、遍历方向和索引边界等信息。
在 MongoDB 的早期版本中, cursor.explain()
返回的cursor
字段具有以下值:
BasicCursor
用于集合扫描,以及BtreeCursor <index name> [<direction>]
用于索引扫描。
有关集合扫描与索引扫描的执行统计信息的更多信息,请参阅分析查询性能。
覆盖查询
当索引涵盖查询时,MongoDB 可以仅使用索引键来匹配查询条件并返回结果。MongoDB 无需检查集合中的文档即可执行查询的任何部分。
当索引覆盖查询时,解释结果中有一个 IXSCAN
阶段不是 FETCH
阶段的子代,在 executionStats
中,totalDocsExamined
是 0
。
在MongoDB的早期版本中, cursor.explain()
返回indexOnly
字段以指示索引是否覆盖查询。
索引并集
对于索引相交计划,结果将包括AND_SORTED
阶段或AND_HASH
阶段,以及详细说明索引的inputStages
数组;例如:
{ "stage" : "AND_SORTED", "inputStages" : [ { "stage" : "IXSCAN", ... }, { "stage" : "IXSCAN", ... } ] }
在 MongoDB 的早期版本中,对于索引交集, cursor.explain()
返回值为Complex Plan
的cursor
字段。
$or
表达式(expression)
如果 MongoDB 为 $or
表达式使用索引,那么结果将包括 OR
阶段和一个详细说明索引的 inputStages
数组;例如:
{ "stage" : "OR", "inputStages" : [ { "stage" : "IXSCAN", ... }, { "stage" : "IXSCAN", ... }, ... ] }
在早期版本的 MongoDB 中,cursor.explain()
返回详细说明索引的 clauses
数组。
$sort
和$group
阶段
当 explain
在 ExecutionStats 或 AllplansEx ecution 详细模式下运行时,$sort
和 $group
阶段会有额外的输出。
排序阶段
如果 MongoDB 无法使用一个或多个索引来获取排序顺序,则结果将包含指示阻塞排序操作的 SORT
阶段。阻塞排序不会阻塞对集合或数据库的并发操作。阻塞是指要求 SORT
阶段在返回任何输出文档之前读取所有输入文档,从而阻止该特定查询的数据流。
如果 MongoDB 需要使用超过 100 MB 的系统内存进行阻塞排序操作,则 MongoDB 将返回错误,除非查询指定了 cursor.allowDiskUse()
。cursor.allowDiskUse()
允许 MongoDB 在处理阻塞排序操作时使用磁盘上的临时文件来存储超过 100 MB 系统内存限制的数据。如果解释计划不包含显式 SORT
阶段,则 MongoDB 可以使用索引来获取排序顺序。