mysql无内置“索引使用率”百分比,sys.schema_unused_indexes仅标识count_fetch=0的索引,sys.schema_redundant_indexes仅识别结构冗余,二者均不反映真实业务价值或写开销,需结合performance_schema计数差值、handler_read%状态及慢日志rows_examined综合判断。

MySQL 没有内置的“索引使用率”百分比字段,sys 库里的视图只是把 performance_schema 和 information_schema 的数据做了聚合包装,不能直接算出“95% 使用率”这种数值——强行除法得出的数字反而会误导你删掉真正有用的索引。
sys.schema_unused_indexes 只筛 COUNT_FETCH = 0 的索引,不是“低使用率”索引
这个视图本质是执行了类似这样的查询:
SELECT object_schema, object_name, index_name
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
AND count_fetch = 0
AND object_schema NOT IN ('mysql', 'information_schema', 'performance_schema');
它只标记自实例启动以来一次都没被 SELECT 命中过的索引。但很多索引可能每周只被跑批任务用一次,COUNT_FETCH = 1 就不会出现在这里,却仍可能被误判为“高使用率”。
-
sys.schema_unused_indexes不区分业务重要性:一个凌晨跑的报表索引,哪怕一年只用一次,也比高频但写多读少的索引更值得保留 - 它不看写开销:
COUNT_INSERT很高但COUNT_FETCH很低的索引(比如只为唯一约束存在的联合索引),sys视图完全不提示 - 重启 MySQL 后所有计数清零,刚上线的新索引会立刻“变幽灵”,此时查
sys.schema_unused_indexes纯属干扰判断
sys.schema_redundant_indexes 识别的是结构重叠,不是使用效率
这个视图检测的是“物理定义上可被另一个索引覆盖”的索引,例如:
- 表上有
INDEX(a)和INDEX(a,b)→INDEX(a)被标为冗余 - 有
UNIQUE(a)和INDEX(a)→ 后者被标为冗余
但它完全不关心这两个索引是否真被用到、用了多少次、用在什么场景。常见陷阱:
- 业务代码里明确
FORCE INDEX(a),但sys.schema_redundant_indexes仍建议删掉INDEX(a)—— 实际不能删 - 联合索引
INDEX(a,b,c)和INDEX(a,b)被标冗余,但如果大部分查询只查WHERE a = ? AND b = ?,而c列极少参与过滤,短索引反而更高效(key_len 更小、缓存更友好) - 视图不会告诉你
INDEX(a,b)是否比INDEX(a,b,c)减少了 20% 的Handler_read_next—— 这种性能差异只能靠压测或慢日志归因
真正要盯的不是“使用率”,而是“有没有白扛写压力”
一个索引有没有价值,核心看它带来的读加速是否远大于写拖累。重点关注这三组指标对比:
- 查
performance_schema.table_io_waits_summary_by_index_usage中同一张表的多个索引:COUNT_FETCH高但COUNT_INSERT + COUNT_UPDATE + COUNT_DELETE极低 → 安全;反之,COUNT_FETCH ≈ 0且COUNT_INSERT持续上涨 → 首选清理目标 - 看全局状态:
SHOW GLOBAL STATUS LIKE 'Handler_read%',如果Handler_read_rnd_next远高于Handler_read_key,说明大量查询没走索引,此时删索引不如先修 SQL - 结合慢日志中的
Rows_examined:某条语句EXPLAIN显示走了索引,但实际Rows_examined = 500000,返回却只有 3 行 → 这个索引可能列顺序错了,或者选择性太差,比“未使用”更危险
别被“使用率”这个词带偏——MySQL 里没有银弹公式。真正有效的动作是:定期快照 performance_schema 计数器,按周/月做差值,再对照业务变更日志,才能分清是索引真没用,还是新功能还没切流。











