首页/数据/数据库速查/判断索引是否真的被用上
SQL 语法52 条

判断索引是否真的被用上

三步确认:EXPLAIN 看 key 命中、优化器 trace 看选择理由、索引使用统计确认长期效果;建了不用的索引只会拖慢写入。

数据库速查数据更新于 2026-10-13

怎么判断索引被用上

索引建了不等于被用。判定要看三层证据:EXPLAIN 的 key 是否命中、key_len 用到了联合索引的第几列;优化器 trace 说明为什么选它或被否决;长期统计确认整体效果。反过来,长期不用的索引只会拖慢写入、占用空间、干扰优化器选择,删之前用不可见索引做灰度印证。

基本信息

适用版本MySQL 5.7 / 8.0(sys 视图在 5.7 起自带)
第一层EXPLAIN / EXPLAIN FORMAT=JSON 看 key、key_len、rows、Extra
第二层optimizer_trace 看候选索引与代价比较
第三层sys.schema_unused_indexes、performance_schema.table_io_waits_summary_by_index_usage
权限要求读 sys 与 performance_schema 需相应 SELECT 权限

典型使用场景

  • 慢查询定位:确认语句是否按预期走了新加的索引
  • 上线前验证:新索引是否被优化器选中,避免白建
  • 清理冗余索引:找出长时间零使用的索引,评估后下线
  • 联合索引设计:用 key_len 反推现有条件用到了第几列,决定是否调整列序
  • 排查计划抖动:同一 SQL 昨天走索引今天不走,用 trace 看代价变化原因

EXPLAIN 与优化器追踪

EXPLAIN 与优化器追踪
-- 第一步:看是否命中索引
EXPLAIN SELECT * FROM appdb.orders WHERE user_id = 42 ORDER BY created_at DESC LIMIT 10;

-- 第二步:打开优化器追踪,只看当前会话的这条语句
SET optimizer_trace = 'enabled=on';
SELECT * FROM appdb.orders WHERE user_id = 42 ORDER BY created_at DESC LIMIT 10;
SELECT * FROM information_schema.OPTIMIZER_TRACE\G
SET optimizer_trace = 'enabled=off';   # 用完立即关闭

长期使用情况盘点

长期使用情况盘点
-- 启动以来一次都没被用过的索引(实例重启后统计归零)
SELECT * FROM sys.schema_unused_indexes;

-- 冗余索引:被其他索引的前缀完全覆盖
SELECT * FROM sys.schema_redundant_indexes;

-- 按索引统计读次数,判断冷热
SELECT object_name, index_name, count_star
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE object_schema = 'appdb' AND object_name = 'orders'
ORDER BY count_star ASC;

证据链对照

证据能回答什么局限
EXPLAIN key本次执行是否用索引、用了哪一个不解释为什么不用别的索引
key_len联合索引实际用到第几列不区分查找还是排序
rows / filtered优化器估算的扫描量与过滤率统计信息陈旧时会严重失真
optimizer_trace候选索引与代价比较的完整过程输出很大,只适合短时定位
schema_unused_indexes长期是否被使用基于启动以来统计,重启即归零
OPTIMIZER_TRACE 输出包含每个候选索引的代价估算,体积很大,只针对单条语句短时开启;会话用完必须关闭,长连接上忘记关闭会持续累积。
用 USE INDEX 强制索引只是应急手段:优化器不选某个索引往往是数据分布或统计信息变了,先 ANALYZE TABLE 或调整索引设计,长期靠强制只会掩盖根因并把风险留给下一次数据变化。

易错点

  • EXPLAIN 里 key 有值就以为没问题:key_len 只覆盖联合索引第一列时,后续条件的过滤仍在回表做,慢依旧
  • 拿 schema_unused_indexes 直接删索引:统计自启动以来累计,刚重启的实例会显示大量「未使用」,误删会引发事故
  • optimizer_trace 开着不关:长连接持续收集,内存与开销累积
  • 只看单次运行结果判定索引有效:执行计划会随数据分布变化,要用监控统计交叉验证
  • 把 USE INDEX 写进正式代码:数据分布一变即成为性能瓶颈,且后续没人敢去掉

数据来源与参考

  • MySQL 8.0 Reference Manual: Optimizer Trace

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌