在MongoDB的聚合管道里,$indexStats是一个专门用来获取集合索引使用统计信息的阶段。它会返回当前集合中每一个索引的访问次数、最近一次被使用的时间戳等数据。这些数据来源于MongoDB实例在内存中维护的索引使用计数器,能够帮助开发者判断索引是否真正发挥作用,而不是凭猜测去增删索引。

一、$indexStats的基本用法
使用$indexStats非常简单,只需要将它作为聚合管道的第一个阶段即可。它不需要任何参数,执行后会针对当前集合输出一个文档数组,每个文档描述一个索引的统计情况。这种设计让我们可以很方便地把结果再接其他阶段做排序或过滤。
下面是一条最基本的查询示例,在myCollection集合上执行索引统计:
// 使用聚合管道获取索引统计
db.myCollection.aggregate([
{ $indexStats: {} }
])
返回结果中常见的字段包括name(索引名称)、key(索引键定义)、accesses.ops(被访问的操作次数)以及accesses.since(计数开始的时间点)。通过这些字段,我们就能知道某个索引从何时开始统计、一共被用了多少次。
1.1 输出字段含义
name字段表示索引的名字,比如_id_或者为某个字段建立的复合索引名称。key字段以文档形式展示索引的排序规则,例如{ age: 1 }代表按age升序建索引。理解这些字段是后续分析的基础。
accesses.ops是一个累加值,每次查询、排序或计数用到了该索引都会加一。accesses.since则是MongoDB进程启动或者索引重建后计数归零的时间,通常用这个时间来判断统计周期长短。
二、结合其他阶段做索引分析
原始统计信息可能很多,我们可以把$indexStats和$sort、$project等阶段组合,快速找出最少使用的索引。这样在清理冗余索引时就有据可依,避免误删高频索引引发性能事故。
例如,以下管道先获取统计,再按访问次数升序排列,并只输出索引名和访问次数:
// 找出访问次数最少的索引
db.myCollection.aggregate([
{ $indexStats: {} },
{ $sort: { "accesses.ops": 1 } },
{ $project: { name: 1, ops: "$accesses.ops", _id: 0 } }
])
上面的代码里,我们用$project重命名了字段并隐藏了_id,让结果更聚焦。这种写法在巡检脚本里很常见,可以直接把输出接入监控平台。
2.1 筛选长期未用的索引
如果accesses.ops为0,且accesses.since距离现在已过去很久,说明该索引可能从未被使用。对于这类索引,在确认业务查询模式后可以考虑drop掉,以减少写入时的索引维护开销。
但要注意,某些索引仅在月度报表或罕见条件查询时才用到,不能单看短期计数就删除。建议结合业务周期观察多次统计结果再做决定。
三、$indexStats的实现原理与限制
$indexStats读取的是MongoDB服务进程内的计数器,并非通过分析慢查询日志得到,因此开销极低,可以在生产环境按需执行。计数在实例重启或索引重建时会被重置,所以它是一个相对统计值而非绝对历史值。
在分片集群中,若在mongos上执行,会聚合各分片返回的数据;若在单个分片主节点执行,则只反映该分片情况。理解这一点对分布式系统的索引评估很重要。
3.1 与explain的区别
explain用来分析单条语句是否走索引,而$indexStats反映索引在一段时间内的整体使用情况。二者互补:explain看单次,indexStats看长期。实际调优时往往先用$indexStats做全局筛查,再对可疑查询用explain深入验证。
另外,$indexStats不会告诉我们某次查询为什么没用索引,它只回答用了没有、用了多少次。因此遇到访问次数异常时,仍需配合explain或日志分析具体语句。
四、实践中的注意事项
因为计数会随重启清零,若想做长期趋势,需要定时抓取并落库保存。可以用脚本每小时跑一次聚合,把结果写进监控集合,这样就能画出索引使用率曲线。
在权限控制严格的环境里,执行聚合需要有对该集合的读权限以及集群监控权限。若返回空数组,先确认集合是否真的有索引,以及当前用户是否被限制。
// 定时保存索引统计的简化示例
const stats = db.myCollection.aggregate([{ $indexStats: {} }]).toArray();
db.index_stats_history.insertMany(
stats.map(s => ({
name: s.name,
ops: s.accesses.ops,
since: s.accesses.since,
recordedAt: new Date()
}))
);
上面这段代码把统计快照存到另一个集合,方便后续对比。注意代码中用了map和箭头函数,实际写入时要确保驱动版本支持对应语法。
4.1 避免误读数据
有时看到某个索引ops很大,但查询依然慢,这可能是因为大量排序或范围扫描导致索引效率不高,而非索引无用。此时应检查explain里的keysExamined与docsExamined比例,而不是只看$indexStats。
总之,$indexStats是MongoDB自带的轻量级索引听诊器,用好了能显著降低盲目维护索引带来的风险,是数据库日常治理中值得常用的手段。
MongoDB聚合管道$indexStats修改时间:2026-08-11 01:33:28