explain是判断索引是否被实际使用的最直接方法:key非null且type为ref/range/const/eq_ref表示有效走索引,type=all为全表扫描;rows应远小于表总行数,extra出现using filesort或using temporary提示排序或分组未利用索引,需结合真实耗时与performance_schema索引命中率综合验证。

用 EXPLAIN 看执行计划是否真正用了索引
加完索引不代表查询就变快了,得确认 MySQL 实际走的是你刚建的索引。直接在 SQL 前加 EXPLAIN,重点看三列:
-
key字段是否显示你的索引名(比如idx_user_email),而不是NULL -
type至少达到ref或range;如果是ALL,说明还是全表扫描 -
rows显示预估扫描行数,应远小于表总行数(比如 100 万行的表,rows超过 5 万就要警惕)
特别注意:Extra 出现 Using filesort 或 Using temporary 时,即使走了索引,排序/分组仍可能拖慢响应。
对比真实查询耗时,别只信理论值
EXPLAIN 给的是估算,真实性能得靠实测。建议在低峰期对同一 SQL 执行多次(至少 5 次),取平均耗时:
- 加索引前:记录
SELECT ... WHERE ...的平均执行时间(如 1200ms) - 加索引后:同样语句再跑一遍(如降到 45ms)
- 注意排除缓存干扰:加
SQL_NO_CACHE(MySQL 5.7 及以前)或先执行RESET QUERY CACHE;8.0+ 可用SELECT SLEEP(0)隔开两次查询
如果耗时没明显下降,大概率是索引没被选中,或者该查询本身不适合走索引(比如返回结果占全表 30% 以上)。
检查写入性能是否被拖累
索引提升读,但必然伤写。重点关注业务高峰期的写操作表现:
- 观察
INSERT/UPDATE/DELETE的平均延迟是否上升(比如从 2ms 升到 5ms) - 监控
Innodb_rows_inserted和Innodb_rows_updated的 QPS 是否下降 - 留意错误日志里是否出现
Lock wait timeout exceeded—— 多索引会加剧锁竞争
一个典型信号:促销期间订单写入超时,查出来发现单表加了 7 个索引,而其中 3 个半年没被 EXPLAIN 过一次。
用 performance_schema 查索引真实命中率
MySQL 8.0+ 提供了更精确的统计视角,比“有没有用”更进一步:“用得多不多”:
- 查某索引被使用的次数:
SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'users' AND INDEX_NAME = 'idx_email';
- 若
COUNT_STAR为 0 或长期低于 10 次/天,这个索引大概率是冗余的 - 结合
SUM_TIMER_WAIT看累计等待时间,判断它是否真在关键路径上
最易被忽略的一点:索引收益不是静态的。业务逻辑变更、数据分布偏移(比如某字段原本高区分度,后来大量插入 NULL 或默认值)、甚至 MySQL 小版本升级都可能让原有索引失效或降级——得定期回检,不是建完就一劳永逸。











