判断索引是否真正生效应优先看type字段:const/eq_ref/ref/range表示有效走索引,index/ALL说明未有效过滤;key非空仅表示被选用,需结合key_len和rows验证实际过滤效果。

不能只看 key 列非空就认为索引被充分使用——它只说明优化器“选了”某个索引,不代表真正过滤了数据、减少了扫描行数或避免了回表。
type 字段才是索引是否真起效的第一判断依据
它直接反映 MySQL 实际访问数据的方式,比 key 更可信:
-
const/eq_ref:精准定位,基本等于索引完全生效(如主键等值查) -
ref:常见且合理,非唯一索引等值匹配(如WHERE status = 1),算有效走索引 -
range:范围查询(>、BETWEEN、IN、LIKE 'abc%'),也算走索引,但需结合rows看扫描量 -
index:全索引扫描,没做 WHERE 过滤,只是遍历索引树——如果rows接近表总行数,和全表扫没区别 -
ALL:全表扫描,索引彻底失效,哪怕key显示了索引名也白搭
典型误判:联合索引 (a,b,c),写 WHERE a = 1 AND c = 3,type 可能是 ref,但 c 实际没参与过滤,key_len 可能只有前两列长度。
key_len + rows 联合验证索引用了几层、省了多少事
key_len 告诉你用了联合索引的前几列,rows 告诉你这个“用”到底有没有减少扫描:
- 索引
idx_user_status_created是(user_id, status, created_at),其中user_id是BIGINT(8 字节)、status是TINYINT NOT NULL(1 字节)、created_at是DATETIME(5 字节) -
key_len = 9→ 只用了user_id + status,created_at没参与 WHERE 过滤 -
key_len = 8→ 即使写了status = 1,也可能因字段允许 NULL、用了OR、或定义不是NOT NULL,导致该列未进索引查找 -
rows如果接近表总行数(比如表有 100 万行,rows = 982341),那基本等于没过滤——别被key的名字骗了
注意:rows 是估算值,统计信息过期(如刚批量导入完没跑 ANALYZE TABLE)会让它严重失真。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
Extra 字段暴露隐藏开销:Using filesort / Using temporary 是性能红灯
即使 type 是 ref 或 range,Extra 里出现某些关键词,说明还有隐性代价:
-
Using index:覆盖索引,不回表,理想状态 -
Using where:索引只做了初步过滤,剩余条件在 Server 层补过滤,正常但不够优 -
Using filesort:排序没走索引,触发额外排序流程(不一定是磁盘文件) -
Using temporary:建了临时表,常见于GROUP BY或ORDER BY非索引列 -
Using index condition:ICP(索引下推),MySQL 5.6+ 支持,把部分 WHERE 下推到存储引擎层执行,是好信号
当 Using filesort 和 Using temporary 同时出现,基本意味着这个查询在当前索引结构下无法避免高开销操作。
possible_keys 有值但 key 为空?优先排查这三类写法问题
这是最常被忽略的“索引明明存在却不用”的场景,重点检查:
- 对索引列用了函数或计算:如
WHERE YEAR(create_time) = 2023、WHERE price * 1.1 > 100 - 字符串字段没加引号导致隐式类型转换:如
WHERE user_id = 123(user_id是VARCHAR) - 用
OR连接了非索引列:如WHERE a = 1 OR b = 2,而只有a有索引 - LIKE 前导通配符:
WHERE name LIKE '%abc'必然走ALL - 索引列参与了
!=、、IS NULL(除非是IS NOT NULL且索引定义为NOT NULL)
复杂点在于:有些失效是组合出现的,比如 WHERE a = 1 AND b > 2 ORDER BY c,即使有联合索引 (a,b,c),c 的排序可能仍触发 Using filesort——因为 b > 2 是范围查询,c 无法继续用于排序。










