mongodb 5.0 并未新增“窗口函数索引”,$setwindowfields 本身不支持建索引;其性能提升源于优化器增强对 $expr 中单字段比较操作(如 $gt)的索引下推能力,需满足 esr 规则且避免嵌套逻辑,验证方式为 explain 中 stage 显示 ixscan。

MongoDB 5.0 并没有新增“窗口函数索引”这种独立索引类型,所谓“窗口函数索引优化”其实是优化器对 $expr 中比较操作符(如 $eq、$gt)命中普通 B-tree 索引能力的增强,不是给 $window 本身建索引。
为什么 $window 查询在 5.0 前容易全表扫描?
4.4 及更早版本中,$setWindowFields 管道阶段无法下推过滤或排序逻辑,导致优化器常放弃使用索引:
- 即使你在
$setWindowFields外层套了$match,若条件含$expr,旧优化器大概率无法将该条件下推到索引扫描层 - 结果是先读全集合文档进内存,再做
$sort和窗口计算,事务内快照持有时间暴增 - 分片集群下,每个分片都重复执行全量扫描,网络和内存压力双高
$expr 中的 $gt/$lt 在 5.0 怎么突然能走索引了?
5.0 修改了查询优化器的表达式下推规则,让 $expr 内部的原子比较操作可被索引引擎识别:
- 必须是单字段比较,例如
{$expr: {$gt: ["$ts", {$dateSubtract: {startDate: "$$now", unit: "hour", amount: 1}}]}} - 不能嵌套多层逻辑(如
{$expr: {$and: [{$gt: ["$a", 1]}, {$lt: ["$b", 10]}]}}),否则仍不走索引 - 索引字段顺序需匹配 ESR 规则:等值字段优先,再接该范围字段;比如
{status: 1, ts: -1}支持{status: "active", $expr: {$gt: ["$ts", ...]}} - 验证是否命中:用
explain("executionStats")查看executionStages.stage是否为IXSCAN,且nReturned远小于totalDocsExamined
为什么 setWindowFields 本身永远不写索引?
$setWindowFields 是聚合阶段,不是 CRUD 操作,它不修改数据,也不生成 oplog,因此完全绕过索引维护机制:
- 窗口计算全程在内存或临时文件中完成,WiredTiger 不为其创建或更新任何索引项
- 即使你对用于
partitionBy或sortBy的字段建了索引,那也只是加速前置的$match或$sort,而非$setWindowFields本身 - 真正影响性能的是
$sort阶段——5.0 优化器能把$project提前下推,减少排序输入体积,这才是内存节省的关键
最容易被忽略的一点:窗口函数的“一致性”完全依赖快照(readConcern: "snapshot"),而不是索引。哪怕你建了完美索引,若事务未显式设置 readConcern,或者在非事务上下文中执行带 $setWindowFields 的聚合,照样可能读到不一致中间态——这不是索引能解决的问题。











