应使用 stats() 查索引总大小、$indexStats 聚合查各索引使用次数;Atlas UI 的 Usage 不准确,删索引前需交叉验证 accesses、explain 和 hint 等场景。

查看索引大小:用 stats() 而不是 getIndexes()
db.collection.getIndexes() 只返回索引定义,不带大小信息。真正能查到索引物理占用的是 stats() 的 indexSize 字段。
执行 db.collection.stats() 后,关注返回中的:
– indexCount:当前集合有多少个索引
– indexSize:所有索引加起来的字节数(含重复键、元数据等)
– totalIndexSize:同 indexSize,是别名
– storageSize 和 size 是数据本身大小,和索引无关
如果想按索引单独看大小,得结合 $indexStats 聚合阶段(见下一条),stats() 无法拆分单个索引的尺寸。
查看索引使用次数:必须用 $indexStats 聚合
db.collection.getIndexes() 或 Atlas UI 显示的 “Usage” 数值,只是主节点自创建/重启以来的累计命中次数,且不包含从节点数据。它不能反映真实全集群使用情况。
要获取准确、可落地的使用统计,必须在每个节点上运行:
db.collection.aggregate([ { $indexStats: {} }, { $group: { _id: "$name", accesses: { $sum: "$accesses" } } } ])
注意点:
– $indexStats 返回每条索引的 accesses 字段(整型计数)
– 如果集合在副本集里,需分别连到 primary 和每个 secondary 执行该聚合
– accesses 为 0 表示该索引从未被查询引擎选中过
– 该统计不区分读写,只统计“被用于执行查询计划”的次数
Atlas 用户别依赖 UI 的 Usage 指标
Atlas 界面里 Indexes 标签页显示的 Usage 值,本质就是主节点的 $indexStats 中 accesses 的快照。它有三个硬伤:
– 不更新实时数据,只在节点重启或索引重建后重置计数
– 完全忽略从节点上的索引使用(哪怕你应用 90% 请求走 secondary)
– 无法过滤时间范围,比如“过去 24 小时用了多少次”
如果你的应用启用了读偏好(readPreference: secondaryPreferred),那 Atlas 显示的 Usage 几乎没参考价值。真要分析,必须手动跑 $indexStats 并汇总各节点结果。
删索引前务必交叉验证 accesses 和查询模式
看到某个索引 accesses: 0 就直接删?不一定安全。
– 复合索引中部分字段可能被其他查询用到(例如 {a:1,b:1,c:1},但只有 {a:1} 查询用到了它)
– 某些低频但关键的后台任务(如 TTL 删除、聚合 pipeline 中的 lookup)可能不常触发,但依赖该索引
– hint() 强制指定索引的查询不会计入 accesses 统计
建议流程:
– 先查 $indexStats 确认长期为 0
– 再用 db.collection.find({...}).explain("executionStats") 验证典型查询是否真的没走它
– 最后检查是否有 hint({}) 或 min()/max() 等显式索引引用

















