必须结合运行时访问统计与查询执行路径双重验证索引使用情况:通过db.collection.stats({indexdetails: true})检查accesses.ops是否为0,再用explain("executionstats")确认ixscan及indexname;索引膨胀率超80%或nscannedobjects/nreturned>3时需优化。

要判断MongoDB中某个集合的索引是否被实际使用、哪些索引长期闲置、读操作是否过度依赖全表扫描,必须结合运行时访问统计与查询执行路径双重验证,不能只看索引是否存在。
查看索引历史访问次数(accesses.ops)
进入目标数据库和集合后,执行:
db.collection.stats({indexDetails: true})
在返回结果中查找 indexDetails 字段下的每个索引对象,重点关注 accesses.ops 字段值——它表示该索引自创建以来被查询命中的总次数。
若某个索引的 accesses.ops 为 0 或长期不增长,说明它未被任何有效查询触发,极可能冗余;但注意:【聚合管道中位于$unwind或$lookup之后的$match不会增加accesses.ops】,这种“伪命中”不计入统计。
用 explain("executionStats") 验证单次查询是否走索引
对典型查询包裹 explain("executionStats"),例如:
db.orders.aggregate([{$match: {status: "shipped", createdAt: {$gte: ISODate("2026-08-01")}}}, {$sort: {total: -1}}]).explain("executionStats")
重点检查 executionStats.executionStages.stage 是否为 IXSCAN(而非 COLLSCAN),同时确认 executionStats.executionStages.indexName 是你预期的索引名。
如果 stage 是 IXSCAN 但 indexName 字段缺失,说明 MongoDB 用了默认_id索引——这往往意味着你的业务字段没建对索引。
计算读写比与索引效率比值
第一步:获取集合基础统计
db.orders.stats()
第二步:提取关键指标
从返回结果中记下以下字段:
· count(文档总数)
· size(数据体积字节)
· storageSize(存储占用字节)
· totalSize(含索引总大小)
· nindexes(索引总数)
第三步:算出索引膨胀率
(totalSize − size) / size × 100%,若超过 80%,说明索引体积已严重挤压数据空间,需审查低效索引。
第四步:评估读写压力分布
执行 mongostat --host localhost:27017 1 5,观察 insert、query、update、delete 四列的每秒数值比例;若 query 远高于 insert+update,且 nscannedObjects / nReturned 比值持续 > 3,则表明读操作缺乏有效索引支撑。
定位未被使用的索引(方法一:扫描 indexDetails.accesses)
方法一:直接筛选零访问索引
db.orders.stats({indexDetails: true}).indexDetails
遍历输出中的每个索引键,检查其 accesses.ops 是否恒为 0。是则标记为待清理候选。
方法二:对比索引定义与活跃查询模式
先用 db.setProfilingLevel(2) 开启全量慢日志,运行 24 小时业务流量;再执行:
db.system.profile.find({millis: {$gt: 50}}).limit(20).forEach(printjson)
提取所有慢查询中的 filter 字段,用它们反向匹配当前索引的 key 定义——若某索引的 key 完全未出现在任何慢查询 filter 中,且 accesses.ops = 0,即可确认废弃。











