MongoDB 5.0+ 默认启用插槽引擎,explain winningPlan 由嵌套 inputStage 变为扁平化带 slots 的结构,如 SLOT_SCAN;explainVersion: 2 标志插槽引擎启用,stage 名称更新(如 SLOT_FETCH),聚合阶段重排更激进,$match 可能被提前,textScore 不显式出现在 explain 中但影响执行路径。

explain 输出中 winningPlan 结构变化明显
MongoDB 5.0 开始默认启用基于插槽(slot-based)的查询引擎,explain 的 winningPlan 不再是嵌套的 inputStage 树形结构,而是扁平化、带 slots 字段的执行计划。旧版(如 4.4 及之前)用经典引擎,输出类似:
{ "stage": "IXSCAN", "inputStage": { "stage": "FETCH", "inputStage": { "stage": "COLLSCAN" } } }
而 5.0+ 常见结构是:
{ "stage": "SLOT_SCAN", "slots": ["slot0", "slot1"], "inputStage": { "stage": "IXSCAN" } }
这不是 bug,是执行模型升级——插槽引擎把中间结果缓存在内存 slot 中,避免重复计算和临时文档拷贝。
容易踩的坑:
- 用正则匹配旧版
explain脚本解析winningPlan的路径(比如硬写.inputStage.inputStage.stage)会直接报错或取空 - 监控系统若依赖 stage 名字做性能归类(如统计 “FETCH 次数”),需同步识别新 stage 类型:
SLOT_FETCH、SLOT_PROJECT等
聚合阶段重排逻辑更激进,$match 不一定“保持原位”
MongoDB 5.0+ 的查询优化器对聚合管道有更强的阶段重排能力,尤其当 $match 条件能命中索引时,即使它写在 $lookup 或 $unwind 后面,优化器也可能把它提前到管道最前——这在 explain 的 stages 数组里能直观看到顺序变化。
但注意:这种重排只发生在「语义等价」前提下。以下情况不会重排:
-
$match引用了$lookup产生的字段(如comments.author) -
$match出现在$facet内部,且 facet 外还有其它阶段 - 使用了
$expr且表达式依赖运行时变量(如$$NOW)
验证方式很简单:对比 db.collection.explain("executionStats").aggregate([...]) 输出中的 stages 数组顺序,别只看原始 pipeline 写法。
textScore 元数据在 explain 中不可见,但影响执行路径
聚合管道中含 $text 的 $match 阶段,在 explain 输出里不会显示 textScore 相关字段,也不会出现 TEXT 阶段名(实际底层仍走全文索引扫描)。但它的存在会强制触发特定执行路径:
- 必须是管道第一个阶段,否则
explain直接报错:"text operator must be the first stage in the pipeline" - 即使你写了
{$match: { $text: {...} }}, {$sort: { score: { $meta: "textScore" } } },explain 的winningPlan里也看不到$sort和$meta的关联,因为$meta是运行时注入,不参与计划生成 - 如果集合没建文本索引,explain 会退化为
COLLSCAN+ 内存过滤,且executionStats.nReturned可能远小于nScannedObjects,这是性能拐点信号
queryPlanner.explainVersion = 2 是分水岭标志
查 explain 结果第一眼就看 queryPlanner.explainVersion:
-
explainVersion: 1→ 经典引擎,适用于 MongoDB ≤ 4.4 -
explainVersion: 2→ 插槽引擎,默认从 5.0 开始,8.0 进一步强化(新增EXPRESS_IXSCAN等 stage)
这个字段比版本号还准——有些用户启用了 5.0 二进制,但通过 setParameter 关闭了插槽引擎,此时 explainVersion 仍是 1。真正决定执行行为的是它,不是 mongod --version。
复杂点在于:同一集群里,不同集合、甚至同一集合的不同查询,可能因索引覆盖度、查询复杂度自动切换引擎(MongoDB 6.0+ 引入 CBR 备份机制),所以单靠一次 explain 不能代表全部查询行为。

















