accesses.ops是mongodb 5.0+中$indexstats返回的索引实际使用次数计数器,统计索引被真正用于查找/排序/范围扫描的次数,而非被选中或查询总次数。

accesses.ops 是什么,不是什么
accesses.ops 是 MongoDB 5.0+ 在 $indexStats 聚合阶段返回的一个计数器,表示该索引自上次重置以来被查询实际“用到”的次数(即命中索引执行了查找/排序/范围扫描等操作),不是被“选中”或“考虑过”的次数,更不是查询总次数。它只统计真正驱动了执行计划的索引访问行为。
- 常见错误现象:看到某个索引
accesses.ops为 0,就立刻删掉——可能它只在低峰期、报表任务或异常路径中被用到,监控窗口太短导致漏采 - 使用场景:适合做周级/月级索引健康度巡检,配合
totalIndexSize判断“高成本低使用”索引 - 性能影响:该指标本身无开销,但频繁调用
$indexStats聚合(尤其在大集合上)会轻微增加读压力
怎么查,查完怎么看
执行 db.collection.aggregate([{$indexStats: {}}, {$sort: {"accesses.ops": -1}}]) 即可获取当前集合所有索引的访问统计。重点关注三类值:
-
accesses.ops === 0:索引长期未被使用,但需确认是否处于冷备逻辑、灰度开关未开、或仅用于唯一约束校验(后者仍会触发索引访问) -
accesses.ops极高但accesses.ops / totalDocsExamined比值偏低:说明索引虽被高频调用,但过滤效果差(例如在低基数字段如status: "active"上建索引),可能拖慢整体查询 - 同一字段组合有多个索引(如
{a:1}和{a:1,b:1}),但{a:1}的accesses.ops远高于{a:1,b:1}:大概率是查询没带b条件,复合索引未被覆盖,此时可考虑收敛索引
为什么不能只看 accesses.ops 做决策
accesses.ops 是个“结果型”指标,不反映索引质量或查询效率。一个索引可能被调用 10 万次,但每次都要扫描 5000 文档;另一个只调用 100 次,却每次都精准定位 1 条——前者 accesses.ops 更高,但实际更该优化或替换。
使用tbot机器ID身份文件配合tsh CLI,通过Teleport访问控制SSH登录托管主机或执行远程命令。
- 必须结合
executionStats.nReturned和executionStats.totalDocsExamined(通过.explain("executionStats")获取)交叉验证 - TTL 索引、哈希索引、文本索引的
accesses.ops行为不同:TTL 索引主要被后台线程扫描,accesses.ops可能持续增长但和业务查询无关;哈希索引在等值查询时才计数,范围查询直接不走索引也不计数 - 分片集群中,
$indexStats返回的是本 shard 的数据,不是全局汇总,需在每个分片分别执行
实操建议:建立索引访问基线
别依赖单次快照。真实环境里,应该每周固定时间跑一次 $indexStats,把 accesses.ops 写入监控表,画趋势图。重点盯住“突降”和“长期归零”两类信号。
- 突降:比如某索引上周是 2 万,这周变 200,要立刻查变更日志——是不是应用改了查询条件?ORM 自动生成语句变了?
- 长期归零(连续 4 周):先用
db.collection.find({xxx}).explain()手动验证该查询是否真没走索引;再检查是否用了$or、$regex、或字段类型不匹配(如字符串查数字)导致索引失效 - 别忘了隐藏索引:
db.collection.hideIndex("idx_name")后,accesses.ops会停止增长,但索引仍在磁盘上——这是安全验证索引可删性的标准做法
真正的难点不在看懂数字,而在于把 accesses.ops 和你的业务请求链路对上号。比如订单服务的“查用户最近 3 笔订单”接口,对应哪个索引、预期多少 ops、波动容忍范围是多少——这些得靠你填,监控工具不会替你猜。










