mongodb 8.0索引扫描策略变更已触发,表现为默认启用indexversion:2、plancacheinvalidation及激进计划淘汰,导致ixscan→collscan回退、索引选择失败、复合索引前缀匹配更严格、text索引互斥、计划缓存污染、统计信息滞后等问题。

确认是否触发了新版本的索引扫描策略变更
MongoDB 8.0 默认启用了 indexVersion: 2(即新的索引格式),同时默认开启 planCacheInvalidation 和更激进的查询计划淘汰逻辑。这会导致部分原本命中高效索引的查询,突然 fallback 到 COLLSCAN 或使用次优索引。
- 运行
db.collection.explain("executionStats")查看实际执行计划,重点比对executionStages.stage是否出现IXSCAN→COLLSCAN或IXSCAN+ 大量filter字段 - 检查
executionStages.indexName是否与预期索引一致;若为null或指向非最优索引,说明索引选择失败 - 用
db.collection.getIndexes()确认所有索引的version字段:值为2表示已重建为新版格式,但不等于性能更好——旧版索引(version: 1)在某些范围查询中反而更稳定
排查复合索引字段顺序与查询谓词匹配度
MongoDB 8.0 的查询优化器对复合索引前缀匹配更严格,尤其当查询含 $or、$in 或混合等值/范围条件时,容易忽略部分字段的索引利用。
- 典型陷阱:
{ status: "active", createdAt: { $gt: ISODate("...") } }查询,若索引是{ createdAt: 1, status: 1 },则status无法被用于索引过滤(非前缀) - 用
db.collection.find().hint({ status: 1, createdAt: 1 }).explain()强制指定索引,对比执行时间与nReturned/totalDocsExamined数值 - 注意
$text索引与普通索引互斥:若存在text索引,且查询未显式hint(),优化器可能放弃其他更优索引
检查 maxTimeMS 和计划缓存污染问题
升级后默认启用更敏感的执行计划淘汰机制,短超时或高并发下易导致频繁重选计划,而新生成的计划未必更优。
- 查看
db.setProfilingLevel(2, { slowms: 10 })后的慢日志,搜索含"planSummary": "COLLSCAN"或"nReturned": 0但"totalDocsExamined"极高的条目 - 运行
db.runCommand({ clearPlanCache: "collection_name" })清空缓存后重测——若性能立刻恢复,说明旧计划缓存被污染 - 避免在应用层硬编码
maxTimeMS小于 50ms:MongoDB 8.0 在超时时会丢弃当前计划并标记为“不可靠”,后续查询可能跳过该索引
验证 WiredTiger 缓存与统计信息是否过期
升级后 collStats 不再自动刷新,WiredTiger 内部统计滞后会导致优化器误判文档分布,从而选错索引。
- 手动触发统计更新:
db.collection.stats({ scale: 1 })后立即执行db.collection.aggregate([{$indexStats:{}}]),确认accesses.ops增长是否同步 - 检查
serverStatus中wiredTiger.cache.maximum bytes configured是否足够;若cache.currentSize长期 > 90%maximum,索引页可能频繁换入换出 - 对写多读少集合,升级后首次运行
db.collection.reIndex()很有必要——旧索引的 page split 状态未被新版引擎识别,可能导致遍历效率下降
indexVersion: 2 对 $regex 前缀匹配的兼容性退化,以及 planCache 在滚动部署期间因节点时间不同步导致的计划漂移。别只盯着 explain 输出,先看 mongod.log 里有没有 “**QueryOptimizer: plan rejected due to staleness**” 这类警告。











