需先启用performance_schema的索引统计功能,再查table_io_waits_summary_by_index_usage视图的COUNT_READ和SUM_TIMER_WAIT等字段判断索引是否被有效命中。

如何用 performance_schema 查索引是否被命中
MySQL 5.6+ 默认开启 performance_schema,但默认不收集索引级别的统计——必须手动启用对应消费者和仪器。不打开就看不到任何索引访问记录,这是最常被忽略的前提。
执行以下语句激活关键组件:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'statements_digest'; UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE 'wait/io/table/%'; UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'statement/sql/select';
注意:wait/io/table/sql/handler 这类底层仪器才真正记录索引读取行为,仅开 statements_digest 不够;TIMED = 'YES' 要设上,否则部分统计字段为 NULL。
之后查 performance_schema.table_io_waits_summary_by_index_usage 视图,重点关注 COUNT_STAR(该索引被使用的总次数)和 COUNT_READ(实际通过该索引做查找的次数)。值为 0 且持续多天,才值得怀疑是否冗余。
识别“伪命中”:为什么 COUNT_READ > 0 还可能是无效索引
某些索引看似被用过,实则只是全表扫描时顺带触发了索引遍历(比如 SELECT * FROM t WHERE id > 0 扫聚簇索引),或优化器选了索引但最终走的是 index_merge 中的某一分支,而非单独依赖该索引。
判断依据要叠加多个维度:
- 检查
table_io_waits_summary_by_index_usage中SUM_TIMER_WAIT是否极低( - 结合
sys.schema_unused_indexes(MySQL 8.0+)视图交叉验证,它会过滤掉仅用于约束/主键/外键的索引 - 用
EXPLAIN FORMAT=TREE重放可疑 SQL,确认执行计划里是否真实出现using index或using index condition - 注意覆盖索引场景:如果一个索引能覆盖查询所有字段,
COUNT_READ可能很高,但它和其他更短的索引功能重叠,仍属冗余
删除前必做的三件事:避免误删主键、唯一约束和隐式依赖
直接 DROP INDEX 可能破坏业务逻辑,尤其当索引承载了约束或被其他工具依赖时。
务必确认:
- 查
INFORMATION_SCHEMA.STATISTICS中NON_UNIQUE = 0且INDEX_NAME != 'PRIMARY'的索引,它们是唯一索引但非主键,删前得确认应用层没做唯一性校验假设 - 运行
SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'your_table',排除CONSTRAINT_NAME非空的索引(即由 UNIQUE/FOREIGN KEY 自动创建的) - 检查慢查询日志或应用 ORM 日志,确认近期是否有 SQL 显式指定
USE INDEX或FORCE INDEX引用该索引名
哪怕 COUNT_READ = 0,只要出现在 KEY_COLUMN_USAGE 里且 CONSTRAINT_NAME 不为空,就不能删。
监控周期与采样陷阱:别只看“最近一小时”
索引使用有明显业务周期性。凌晨批处理、周末报表、促销时段的查询模式完全不同。只查过去 1 小时或 1 天的数据,大概率误判。
建议做法:
- 将
table_io_waits_summary_by_index_usage每天快照一次,保留至少 7 天,观察趋势而非单点值 - 对 OLTP 表,重点看工作日 9:00–18:00 的
COUNT_READ累计值;对报表表,则盯住每天凌晨 2:00–4:00 的峰值 -
performance_schema统计是累积型的,重启 MySQL 后清零——如果实例刚重启不久,所有索引都显示 0,不代表真没用
真正难的不是查哪个索引没被用,而是确认它在所有业务路径、所有时间窗口、所有参数组合下都始终未被触达。这点靠自动脚本很难全覆盖,得结合业务发布节奏人工对齐。











