为了返回有关查询计划 和查询计划执行统计信息,MongoDB 提供了以下方法:
要了解重要的解释结果字段以及如何加以解释,请参阅解释“解释计划结果”。
重要
explain 忽略计划缓存。相反,系统会生成一组候选计划,并在不咨询计划缓存的情况下选择获胜者。此外,explain 会阻止 MongoDB 查询规划器缓存获胜计划。
注意
此页面仅显示最重要的输出字段,未记录供内部使用的字段。输出中列出的字段可能会发生变化。
解释输出结构
explain 结果将查询计划显示为阶段树。输出结构可能因操作使用的查询引擎而异。操作可以使用经典查询引擎或基于插槽的执行查询引擎。
参阅以下示例,了解这两个执行引擎的输出结构有何不同:
winningPlan: { stage: <STAGE1>, ... inputStage: { stage: <STAGE2>, ... inputStage: { stage: <STAGE3>, ... } } },
winningPlan: { queryPlan: { stage: <STAGE1>, ... inputStage: { stage: <STAGE2>, ... inputStage: { stage: <STAGE3>, ... } } } slotBasedPlan: { ... } },
每个阶段都将其生成的文档或索引键传递到父节点。叶节点访问集合或索引。内部节点使用由子节点产生的文档或索引键。根节点指示 MongoDB 最终派生出结果集的阶段。
阶段是对操作的描述。例如:
COLLSCAN用于集合扫描IXSCAN用于扫描索引键FETCH用于检索文档GROUP用于对文档进行分组SHARD_MERGE用来合并来自分片的结果SHARDING_FILTER用于从分片中筛掉孤儿文档TS_MODIFY用于修改时间序列集合BATCHED_DELETE用于在内部批处理的多个文档删除(从 MongoDB 6.1 开始)EOF用于当阶段处于流结束时EXPRESS为一组有限的查询提供阶段,这些查询可以绕过常规查询计划,使用优化的索引扫描计划(版本 8.0 中的新功能。)EXPRESS阶段可以是以下之一:EXPRESS_CLUSTERED_IXSCANEXPRESS_DELETEEXPRESS_IXSCANEXPRESS_UPDATE
解释 MongoDB 5.1 和更高版本的输出
本部分显示 MongoDB 5.1 及更高版本的 explain 输出。要查看旧版本 MongoDB 的解释输出,请参阅该版本的文档。
queryPlanner
explain.queryPlanner 信息详细说明了查询优化器选择的计划。
这些示例可能结合了 MongoDB 的经典执行引擎和基于槽位的执行引擎的输出结构。它们并不具有代表性。您的输出可能与之有巨大差异。
对于未分片的集合,explain 将返回以下 queryPlanner 信息:
queryPlanner: { namespace: <string>, indexFilterSet: <boolean>, parsedQuery: { ... }, planCacheShapeHash: <hexadecimal string>, planCacheKey: <hexadecimal string>, maxIndexedOrSolutionsReached: <boolean>, maxIndexedAndSolutionsReached: <boolean>, maxScansToExplodeReached: <boolean>, winningPlan: { stage: <STAGE1>, type: <string>, inputStage: { stage: <string>, ... } }, rejectedPlans: [ <candidate plan1>, ] }
从MongoDB 8.0 开始,现有的 queryHash字段将复制到名为 planCacheShapeHash 的新字段中。 如果您使用的是早期MongoDB版本,则只能看到 queryHash字段。 未来的MongoDB版本将删除已弃用的 queryHash字段,您需要改用 planCacheShapeHash字段。
对于分片集合,explain 包括核心查询规划器和 shards 字段中每个被访问分片的服务器信息:
{ queryPlanner: { mongosPlannerVersion: <int> winningPlan: { stage: <STAGE1>, type: <string>, shards: [ { shardName: <string>, connectionString: <string>, serverInfo: { ... }, namespace: <string>, indexFilterSet: <boolean>, parsedQuery: { ... }, querySettings: { ... }, planCacheShapeHash: <hexadecimal string>, planCacheKey: <hexadecimal string>, maxIndexedOrSolutionsReached: <boolean>, maxIndexedAndSolutionsReached: <boolean>, maxScansToExplodeReached: <boolean>, winningPlan: { stage: <STAGE1>, type: <string>, inputStage: { stage: <string>, ... } }, rejectedPlans: [ <candidate plan1>, ] } ] } } }
从MongoDB 8.0 开始,现有的 queryHash字段将复制到名为 planCacheShapeHash 的新字段中。 如果您使用的是早期MongoDB版本,则只能看到 queryHash字段。 未来的MongoDB版本将删除已弃用的 queryHash字段,您需要改用 planCacheShapeHash字段。
explain.queryPlanner包含查询优化器所选查询计划的相关信息。
explain.queryPlanner.namespace一个字符串,使用数据库的名称和查询访问的集合指定该命名空间。该命名空间的格式为
<database>.<collection>。
explain.queryPlanner.querySettings如果设置了查询设置,则
querySettings包含有关应用于查询结构的查询设置的详细信息。要添加查询设置并浏览示例(其中包括
explain()输出和querySettings),请参阅setQuerySettings。8.0版本新增。
explain.queryPlanner.planCacheShapeHash从MongoDB 8.0 开始,现有的
queryHash字段将复制到名为planCacheShapeHash的新字段中。 如果您使用的是早期MongoDB版本,则只能看到queryHash字段。 未来的MongoDB版本将删除已弃用的queryHash字段,您需要改用planCacheShapeHash字段。一个十六进制字符串,表示计划缓存查询结构的哈希值,并且仅依赖于计划缓存查询结构。
planCacheShapeHash可以帮助识别具有相同计划缓存查询结构的慢查询(包括写入操作的查询筛选条件)。注意
与任何哈希函数一样,两个不同的计划缓存查询结构可能会产生相同的哈希值。但是,不同计划缓存查询结构之间不太可能发生哈希冲突。
有关
planCacheShapeHash和planCacheKey的更多信息,请参阅 planCacheShapeHash 和 planCacheKey。
explain.queryPlanner.planCacheKey与此查询关联的计划缓存条目的键的哈希值。
与
explain.queryPlanner.planCacheShapeHash不同,explain.queryPlanner.planCacheKey是计划缓存查询结构和该结构当前可用索引的函数。具体来说,如果添加或删除可以支持查询结构的索引,则planCacheKey值可能会更改,但planCacheShapeHash值不会更改。有关
planCacheShapeHash和planCacheKey的更多信息,请参阅 planCacheShapeHash 和 planCacheKey。
explain.queryPlanner.optimizationTimeMillis查询规划器在查询优化上花费的时间(以毫秒为单位)。此结果不包括优化内部
$lookup查询所花费的时间。
explain.queryPlanner.optimizedPipeline一个布尔值,表明整个聚合管道操作已被优化掉,改用查询计划执行阶段树来实现。
例如,以下聚合操作可以通过查询计划执行树来完成,而不使用聚合管道。
db.example.aggregate([ { $match: { someFlag: true } } ] ) 仅当值为
true时,该字段才存在,并且仅适用于解释聚合管道操作。为true时,由于管道已被优化掉,所以输出中不会出现聚合阶段信息。
explain.queryPlanner.winningPlan详细说明查询优化器所选计划的文档。
explain.queryPlanner.winningPlan.stage一个表示阶段名称的字符串。
每个阶段都包含针对该阶段的信息。例如,
IXSCAN阶段包括索引边界和索引扫描的其他特定数据。如果一个阶段有一个或多个子阶段,则该阶段将有一个inputStage或inputStages。如果该操作使用经典查询执行引擎,则会显示此字段。
explain.queryPlanner.winningPlan.type如果将
stage设立为"EOF",则type是一个字符串,表示 EOF 阶段的原因:"nonExistentNamespace":表示查询命名空间不存在。"predicateEvalsToFalse":表示表达式简化确定该查询不会匹配任何文档。
explain.queryPlanner.winningPlan.inputStages描述子阶段的一系列文档。子阶段为父阶段提供文档或索引键。如果父阶段有多个子节点,则该字段存在。例如,$or 表达式的阶段可能会消耗多个来源的输入。
如果该操作使用经典查询执行引擎,则会显示此字段。
explain.queryPlanner.winningPlan.isCached一个布尔值,用于指示赢得计划是否在计划缓存中。
对于获胜计划和被拒绝计划之间最多一个计划,此字段为
true。 如果查询没有缓存计划,则对于获胜计划和被拒绝的计划,该字段为false。
explain.queryPlanner.winningPlan.queryPlan一份详细说明查询优化器所选计划的文档。MongoDB 将计划表示为阶段树。
如果查询使用基于槽位的执行查询引擎,则此文档出现。
5.1 版本中的新功能。
explain.queryPlanner.winningPlan.queryPlan.stage一个表示阶段名称的字符串。
每个阶段都包含针对该阶段的信息。例如,
IXSCAN阶段包括索引边界和索引扫描的其他特定数据。
explain.queryPlanner.winningPlan.queryPlan.type如果将
stage设立为"EOF",则type是一个字符串,表示 EOF 阶段的原因:"nonExistentNamespace":表示查询命名空间不存在。"predicateEvalsToFalse":表示表达式简化确定该查询不会匹配任何文档。
explain.queryPlanner.winningPlan.queryPlan.planNodeId标识执行计划中每个阶段的唯一整型字段。字段包含在整个
explain结果的所有阶段中。5.1 版本中的新功能。
explain.queryPlanner.winningPlan.slotBasedPlan一份文档,包含有关基于槽位的查询执行计划树和阶段的信息。供 MongoDB 内部使用。
5.1 版本中的新功能。
explain.queryPlanner.winningPlan.slotBasedPlan.stages包含基于插槽的查询执行计划中每个阶段的信息的字符串,包括执行顺序、操作和插槽分配。供 MongoDB 内部使用。
从 MongoDB 8.0开始,如果查询使用块处理,则
block_to_row和ts_bucket_to_cellblock会出现在stages输出中。在版本8.0中进行了更改。
explain.queryPlanner.rejectedPlans查询优化器考虑和拒绝的候选计划数组。如果没有其他候选计划,则数组可能为空。
被拒绝的计划具有与
explain.queryPlanner.winningPlan相同的字段。从 MongoDB 8.0 开始,被拒绝的查询计划只包含查询的
find部分。在以前的版本中,被拒绝的计划可以包含聚合阶段,例如$group。查询规划器不使用这些聚合阶段来选择获胜计划,因此rejectedPlans字段只包含查询中用于选择获胜计划的部分。
executionStats
返回的 explain.executionStats 信息详细说明了获胜计划的执行情况。为了在结果中包含 executionStats,您必须在如下位置运行解释:
allPlansExecution 冗余模式。使用
allPlansExecution模式以包含计划选择过程中捕获的部分执行数据。
这些示例可能结合了 MongoDB 的经典执行引擎和基于槽位的执行引擎的输出结构。它们并不具有代表性。您的输出可能与之有巨大差异。
对于未分片的集合,explain 将返回以下 executionStats 信息:
executionStats: { executionSuccess: <boolean>, nReturned: <int>, executionTimeMillis: <int>, totalKeysExamined: <int>, totalDocsExamined: <int>, executionStages: { stage: <STAGE1> nReturned: <int>, executionTimeMillisEstimate: <int>, opens: <int>, // Starting in MongoDB 5.1 closes: <int>, // Starting in MongoDB 5.1 works: <int>, advanced: <int>, needTime: <int>, needYield: <int>, saveState: <int>, restoreState: <int>, isEOF: <boolean>, ... inputStage: { stage: <STAGE2>, nReturned: <int>, ... numReads: <int>, // Starting in MongoDB 5.1 ... executionTimeMillisEstimate: <int>, ... spills: <long long>, spilledBytes: <long long>, spilledRecords: <long long>, spilledDataStorageSize: <long long>, ... inputStage: { ... } } }, allPlansExecution: [ { nReturned: <int>, executionTimeMillisEstimate: <int>, totalKeysExamined: <int>, totalDocsExamined:<int>, executionStages: { stage: <STAGEA>, nReturned: <int>, executionTimeMillisEstimate: <int>, ... inputStage: { stage: <STAGEB>, ... inputStage: { ... } } } }, ... ] operationMetrics: { cpuNanos: <int>, cursorSeeks: <int>, docBytesRead: <int>, docBytesWritten: <int>, docUnitsRead: <int>, docUnitsReturned: <int>, docUnitsWritten: <int>, idxEntryBytesRead: <int>, idxEntryBytesWritten: <int>, idxEntryUnitsRead: <int>, idxEntryUnitsWritten: <int>, totalUnitsWritten: <int>, keysSorted: <int>, sorterSpills: <int> } }
对于分片集合,explain 包括每个访问的分片的执行统计信息。
executionStats: { nReturned: <int>, executionTimeMillis: <int>, totalKeysExamined: <int>, totalDocsExamined: <int>, executionStages: { stage: <STAGE1> nReturned: <int>, executionTimeMillis: <int>, opens: <int>, // Starting in MongoDB 5.1 closes: <int>, // Starting in MongoDB 5.1 totalKeysExamined: <int>, totalDocsExamined: <int>, totalChildMillis: <NumberLong>, shards: [ { shardName: <string>, executionSuccess: <boolean>, executionStages: { stage: <STAGE2>, nReturned: <int>, executionTimeMillisEstimate: <int>, ... chunkSkips: <int>, inputStage: { stage: <STAGE3>, ... numReads: <int>, // Starting in MongoDB 5.1 ... spills: <long long>, spilledBytes: <long long>, spilledRecords: <long long>, spilledDataStorageSize: <long long>, ... 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扫描的索引项数。
explain.executionStats.totalKeysExamined对应于早期版本的 MongoDB 中的cursor.explain()返回的nscanned字段。
explain.executionStats.totalDocsExamined查询执行过程中检查的文档数量。检查文档的常见查询执行阶段是
COLLSCAN和FETCH。注意
explain.executionStats.totalDocsExamined是指已检查的文档总数,而非返回的文档数量。例如,阶段可以按照顺序检查文档以应用过滤器。如果文档被过滤掉,则说明它已被检查过,但不会纳入查询结果集返回。如果在查询执行过程中多次检查了一个文档,
explain.executionStats.totalDocsExamined会对每次检查进行计数。也就是说,explain.executionStats.totalDocsExamined不是所检查的唯一文档的总数。
explain.executionStats.executionStages以阶段树的形式详细说明获胜计划的执行情况;即一个阶段可以有一个
inputStage或多个inputStages。从 MongoDB 5.1 开始,一个阶段可以具有以下输入阶段:
thenStageelseStageinnerStageouterStage
每个阶段都包含针对该阶段的执行信息。
explain.executionStats.executionStages.works指定查询执行阶段执行的“工作单元”数量。查询执行将其工作划分为多个小单元。“工作单元”可能包括检查单个索引键、从集合中获取单个文档、将投影应用于单个文档或进行内部簿记。
如果该操作使用经典查询执行引擎,则会显示此字段。
explain.executionStats.executionStages.isEOF指定执行阶段是否已到达流结束:
如果为
true或1,则执行阶段已到达流结束。如果为
false或0,则该阶段可能仍有结果要返回。考虑一个具有限制的查询,其执行阶段由LIMIT个阶段组成,输入阶段为IXSCAN。如果查询返回的结果超过指定的限制,则LIMIT阶段将报告isEOF: 1,但其底层的IXSCAN阶段将报告isEOF: 0。
explain.executionStats.executionStages.inputStage每个
inputStage可以有不同的字段,具体取决于inputStage.stage的值。下表描述了可能的字段以及它们可以出现在哪些阶段。每个
inputStage可以具有另一个inputStage作为字段。请参阅解释输出结构。字段说明适用阶段docsExamined指定在查询执行阶段扫描的文档数量。
COLLSCAN,FETCHkeysExamined对于扫描索引的查询执行阶段,
keysExamined是在索引扫描过程中检查的界内和界外键的总数。如果索引扫描由单个连续范围的键组成,则仅需要检查界内键。如果索引边界由多个键范围组成,则索引扫描执行过程可能会检查界外键,以便从一个范围的末尾跳到下一个范围的开头。IXSCANnumReads在查询执行阶段扫描的文档或检查的索引键的数量。
5.1 版本中的新功能。
COLLSCAN,IXSCANseeks为了完成索引扫描而必须让索引游标搜索新位置的次数。
IXSCANusedDisk该阶段是否已写入磁盘。
5.3 版本中的新增功能。
GROUPspills该阶段溢出到磁盘的次数。
8.2版本新增。
GROUP,SORTspilledBytes写入磁盘的数据总量(以字节为单位)。
8.2版本新增。
GROUP,SORTspilledRecords溢出到磁盘的单条记录总数。
8.2版本新增。
GROUP,SORTspilledDataStorageSize溢出数据使用的总磁盘空间(以字节为单位)。
8.2版本新增。
GROUP,SORT
explain.executionStats.allPlansExecution包含在计划选择阶段为中标和被拒计划捕获的部分执行信息。该字段仅在
explain以allPlansExecution详细模式运行时出现。
explain.executionStats.operationMetrics包含资源消耗统计信息,只要它们不为零。仅当
explain在executionStats详细模式或更高模式下运行并且profileOperationResourceConsumptionMetrics已启用时,该字段才会出现。警告
MongoDB 8.2 删除
profileOperationResourceConsumptionMetrics。因此,依赖于operationMetrics的代码不起作用。
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> } ...
具有 管道阶段的查询的执行计划统计信息$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 页面。
其他字段为:
搜索查询的执行计划统计信息
8.1版本新增。
解释结果包括使用 $search、$searchMeta 或$vectorSearch 管道阶段的查询的执行统计信息。要包含搜索查询的执行统计信息,请在以下执行详细模式之一运行explain 命令:
MongoDB返回仅使用经典引擎的搜索和向量搜索查询的执行统计信息。
有关搜索和向量搜索查询解释结果的更多详细信息,请参阅:
集合扫描(collection scan)
如果查询规划器选择集合扫描,解释结果将包含 COLLSCAN 阶段。
如果查询规划器选择索引,解释结果将包含 IXSCAN 阶段。该阶段包括索引键模式、遍历方向和索引边界等信息。
从 MongoDB 5.3 开始,如果查询规划器为集群化集合选择了集群化索引,且查询包含定义要搜索的索引部分的边界,则解释结果会包含一个 CLUSTERED_IXSCAN 阶段。该阶段包含有关集群化索引键和索引边界的信息。
如果查询规划器为集群化集合选择集群化索引,且查询不包含边界,则查询将执行无边界集合扫描,解释结果包括 COLLSCAN 阶段。
注意
notablescan 参数不允许使用集群索引的无界查询,因为这些查询需要完整的集合扫描。
有关集合扫描的执行统计数据的更多信息,请参阅解释“解释计划结果”。
覆盖查询
当索引涵盖查询时,MongoDB 可以仅使用索引键来匹配查询条件并返回结果。MongoDB 无需检查集合中的文档即可执行查询的任何部分。
当索引覆盖查询时,解释结果中有一个 IXSCAN 阶段不是 FETCH 阶段的子代,在 executionStats 中,explain.executionStats.totalDocsExamined 是 0。
$or 表达式(expression)
如果 MongoDB 为 $or 表达式使用索引,那么结果将包括 OR 阶段和一个详细说明索引的 explain.queryPlanner.winningPlan.inputStages 数组;例如:
{ stage: 'OR', inputStages: [ { stage: 'IXSCAN', ... }, { stage : 'IXSCAN', ... }, ... ] }
在早期版本的 MongoDB 中,cursor.explain() 返回详细说明索引的 clauses 数组。
$sort 和$group 阶段
当 explain 在 ExecutionStats 或 AllplansEx ecution 详细模式下运行时,$sort 和 $group 阶段会有额外的输出。
阶段 | 字段 | 类型 | 说明 |
|---|---|---|---|
| long |
| |
| 布尔 |
| |
| long long |
| |
| long long | 压缩前在 | |
| long long | 溢出到磁盘的单条记录总数。 | |
| long long | 溢出数据使用的总磁盘空间(以字节为单位)。 | |
| 布尔 |
| |
| long long |
| |
| long long | 压缩前在 | |
| long long | 溢出到磁盘的单条记录总数。 | |
| long long | 溢出数据使用的总磁盘空间(以字节为单位)。 |
排序阶段
如果MongoDB无法使用一个或多个索引来获取排序顺序,则结果将包含一个指示内存中排序操作的 SORT 阶段。如果解释计划不包含显式 SORT 阶段,则MongoDB使用索引来获取排序顺序。
查询结构哈希
从 MongoDB 8.0 开始,explain 输出以下字段: