是什么
隐藏索引(hidden index)是 MongoDB 4.4 引入的上线前验证手段:hideIndex 之后索引仍然存在、仍然随写入维护,但对查询规划器不可见。于是可以先把它「假装删掉」,观察线上查询是否出现全表扫描、性能是否退化,确认无用再真正 dropIndex,确认有用随时 unhideIndex 恢复。它把「删索引」这个不可逆动作拆成了可回退的两步。
基本信息
| 隐藏 | db.collection.hideIndex("idx_name") 或 hideIndex({ status: 1 }) |
|---|---|
| 恢复 | db.collection.unhideIndex("idx_name") |
| 创建即隐藏 | createIndex({...}, { hidden: true }) |
| 版本要求 | MongoDB 4.4 及以上 |
| 硬限制 | _id 索引不能隐藏 |
| 查询状态 | db.collection.getIndexes() 中 hidden 字段为 true |
典型使用场景
- 索引下线前验证:先隐藏,观察若干天慢查询与扫描量,确认无查询依赖再删除
- 新索引上线前对照:建好后先保持隐藏,用 hint 或 explain 对比,避免新索引抢占计划
- 容量评估:隐藏冗余索引并观察一段时间,为最终清理提供数据支撑
- 写入压力排查:确认某些索引只服务于已下线的报表功能,隐藏后写放大是否缓解可以量化
- 变更窗口操作:需要短时间改变查询计划时,用隐藏代替删除,回退成本最低
隐藏与验证
隐藏与验证
db.orders.getIndexes().map(i => ({ name: i.name, hidden: i.hidden === true })) # 先列出索引与隐藏状态
db.orders.hideIndex("status_ts") # 让规划器不再选择该索引
db.orders.find({ status: "paid" }).explain("executionStats") # 看 winningPlan 是否退化为 COLLSCAN
db.orders.find({ status: "paid" }).hint({ status: 1 }) # 对照实验:强制走另一个索引
db.orders.unhideIndex("status_ts") # 观察期内发现问题,立刻恢复
db.orders.dropIndex("status_ts") # 确认长期无用后再删除隐藏后的观察项
| 观察对象 | 正常表现 | 异常表现 |
|---|---|---|
| explain 的 winningPlan | 仍走其他可用索引或保持索引扫描 | 出现 COLLSCAN |
| totalDocsExamined | 与隐藏前量级相当 | 成倍甚至数量级上升 |
| 慢查询日志 | 数量无明显变化 | 新增大量慢查询 |
| 写入延迟 | 略有下降(索引维护仍在,只是不被选中) | 不要期待明显改善 |
隐藏期间索引依然随写入维护、依然占用磁盘,所以隐藏不是省资源的动作,而是零风险的验证动作;真正释放写入开销只能靠 dropIndex。
在副本集与分片集群上隐藏索引是配置变更,需要主节点与多数成员确认;生产环境操作前先确认副本集状态健康,避免在选举或维护窗口内叠加配置变更。