mongodb 7.0无查询结果缓存,仅支持查询计划缓存和wiredtiger数据页缓存;$match前置可复用计划缓存,因按查询形状匹配;wiredtiger缓存自动管理但易被刷空;视图可固化管道形状;explain("executionstats")是验证缓存生效的唯一可靠方式。

MongoDB 7.0 **没有查询结果缓存(query result cache)机制**,所谓“利用缓存加速聚合查询”实际是指复用**查询计划缓存(plan cache)** 和 **索引数据页缓存(WiredTiger cache)** ——这两者是自动生效的底层优化,不能手动开关或预热,但可以被显式干扰或破坏。
为什么 $match 前置能“触发缓存复用”
查询计划缓存按“查询形状(query shape)”匹配:即操作符、字段名、结构一致,值可不同。例如:
db.orders.aggregate([{ $match: { status: "completed", created_at: { $gte: ISODate("2024-01-01") } } }, { $group: { _id: "$user_id", total: { $sum: "$amount" } } }])
和
db.orders.aggregate([{ $match: { status: "shipped", created_at: { $gte: ISODate("2024-06-01") } } }, { $group: { _id: "$user_id", total: { $sum: "$amount" } } }])
属于同一查询形状,只要索引未变、DDL未发生,第二次执行会直接复用第一次选中的执行计划(如索引扫描路径),跳过候选计划评估阶段。
- 必须保证 $match 在第一个阶段:否则查询形状不同(比如 $project 在前),无法命中缓存
-
避免在 $match 中混用变量类型:如有时传
"123"字符串,有时传123数字,会被视为两个不同形状 -
不要在管道里动态拼接字段名:如用
$expr+$concat构造匹配条件,会破坏形状稳定性
WiredTiger 缓存不是“你配它就快”,而是“你别乱动它”
WiredTiger 的 page cache 会自动缓存最近访问的索引页和文档页,对高频聚合的关键作用是:减少磁盘 I/O。但它极易被以下操作清空或挤占:
-
执行
db.runCommand({ flushRouterConfig: 1 })或重启 mongod:整个 cache 清零 -
大量写入或
$out/$merge操作:cache 优先服务写入,读取缓存被快速淘汰 -
设置过小的
wiredTigerCacheSizeGB:默认是物理内存的一半,若手动压到 1GB 而集合索引总大小 8GB,则热点页反复换入换出 -
聚合中启用
allowDiskUse: true:临时磁盘文件不进 WT cache,且可能引发 IO 竞争,反而拖慢后续内存查询
视图(view)不是缓存,但能稳定查询形状
创建视图本质是保存一个聚合管道定义,每次读取都走完整 pipeline。它的价值在于:
- 固化 $match 条件位置:避免应用层误把 $sort 或 $lookup 放到 $match 前面
-
统一字段投影(
$project):防止下游意外请求全量文档,放大内存与网络压力 - 绕过某些 plan cache 失效场景:比如应用频繁改写聚合代码导致形状变化,而视图定义不变,cache 更持久
注意:db.createView("sales_summary", "orders", [ { $match: { status: "completed" } }, { $group: { _id: "$region", revenue: { $sum: "$amount" } } } ]) 创建后,所有 db.sales_summary.find() 都等价于该 pipeline,形状固定。
explain("executionStats") 是唯一能验证“缓存是否起效”的方式
真正关心是否复用计划缓存,不能看响应时间(受网络、客户端、系统负载干扰),要看执行统计里的两个字段:
-
executionStats.planSummary:如果两次执行返回完全相同的字符串(如IXSCAN { status: 1, created_at: 1 }),说明用了同一计划 -
executionStats.executionStages.advanced对比差异:若第二次 advanced 数明显小于第一次,大概率复用了缓存页(没从磁盘重读) -
executionStats.nReturned和executionStats.totalDocsExamined应保持稳定;若后者突增,说明索引失效或 plan cache 被刷新
执行时加 .explain("executionStats") 即可,无需额外配置——这是诊断真实瓶颈的唯一直观依据,其他“感觉变快了”都是噪声。











