应使用 plancacheclear 命令按查询形状精准清除单个缓存,或用 db.collection.getplancache().clear() 清空整个集合缓存;切勿误用 flushrouterconfig,它仅影响分片路由元数据,与查询计划无关。

查不到预期执行计划、explain() 显示 stage: COLLSCAN 却明明有索引、反复执行同一查询却总走不同索引——这些不是数据问题,是查询计划缓存(plan cache)出了异常。直接清空对应缓存即可,但必须选对命令、指定对参数,否则无效或误删。
用 planCacheClear 命令精准清除单个查询结构
这是最常用也最容易出错的场景:某个特定查询(比如带 sort 和 projection 的聚合)总选错执行计划。不能只清整个集合,得按“查询形状”清除。
-
query字段必须传入与原始查询**字段名一致、值任意**的文档,例如原查询是{ status: "pending", createdAt: { $gt: ISODate("...") } },这里只需传{ status: 1, createdAt: { $gt: null } }—— 值不重要,结构(字段名+操作符)必须完全匹配 -
sort和projection如果原查询用了,就必须一并带上,否则 MongoDB 认为是另一个查询结构 - 执行示例:
db.runCommand({ planCacheClear: "orders", query: { status: 1 }, sort: { createdAt: -1 }, projection: { _id: 1, total: 1 } }) - 错误示范:漏掉
sort或把{ status: "pending" }写成{ status: { $eq: "pending" } }—— 形状不一致,命令成功但实际没删到目标计划
用 PlanCache.clear() 清空整个集合的缓存
当你刚加了新索引、改了查询逻辑,或者发现多个查询都开始走错路,说明整个集合的 plan cache 已混乱,需要彻底重置。
- 必须通过集合对象调用:
db.orders.getPlanCache().clear(),不能写成db.getPlanCache().clear()(会报错) - 该方法不接受任何参数,也不返回详细结果;如需确认是否生效,后续执行
db.orders.getPlanCache().list()查看剩余条目数 - 注意权限:启用鉴权时,用户需具备
planCacheWrite角色,否则提示"not authorized on ... to execute command planCacheClear" - 不推荐在生产高峰期间执行,因为首次查询会触发重新生成执行计划,可能短暂变慢
别碰 flushRouterConfig,它和查询计划无关
网上很多教程把 flushRouterConfig 当作“清缓存万能命令”,这是严重误导。它只影响分片集群的路由元数据缓存(比如 chunk 分布、shard key 路由表),对查询执行计划缓存完全无效。
- 在非分片集群上执行
db.adminCommand({ flushRouterConfig: 1 })会直接报错:"flushRouterConfig can only be run on sharded clusters" - 即使在分片集群上运行,它也不会让
explain()中的stage变回IXSCAN,解决不了你的查询性能问题 - 真正要清理的是查询计划缓存,不是路由缓存 —— 两者存储位置、更新机制、触发条件完全不同
MongoDB 8.0+ 用户注意:索引筛选器已废弃,改用查询设置
如果你还在用 db.runCommand({ createIndexFilter: ... }) 或类似旧方式“固定”查询计划,现在会失效。MongoDB 8.0 起强制使用 setQuerySettings 替代。
-
setQuerySettings是持久化配置,支持跨节点同步,且能绑定到具体查询形状(含query、sort、projection) - 旧的
planCacheClear命令仍可用,但若你依赖索引筛选器来引导计划选择,升级后必须迁移,否则清完缓存也没用 —— 新计划仍可能绕过你期望的索引 - 迁移示例:
db.runCommand({ setQuerySettings: { query: { status: 1 }, sort: { createdAt: -1 }, settings: { indexHints: [ { "status_1_createdAt_-1": 1 } ] } } })
真正关键的不是“清”,而是“清得准”:查 db.collection.getPlanCache().list() 确认异常计划是否存在,再按形状构造 planCacheClear 参数;如果批量异常,优先用 PlanCache.clear();永远不要用 flushRouterConfig 对付查询慢——那是方向反了。











