EXPLAIN中key为NULL仅表示优化器未选择索引,并非绝对失效;根本原因是成本估算认为全表扫描更优,尤其受NULL占比、联合索引最左前缀规则及统计准确性影响。

EXPLAIN 的 key 字段为 NULL 就表示索引失效
直接看 EXPLAIN 输出的 key 列:值为 NULL 说明 MySQL 完全没用索引,走了全表扫描。这不是“可能没用”,而是确定没用——哪怕你建了 5 个索引,只要 key 是 NULL,就等于白建。
注意别只盯 possible_keys:它只是列出“理论上可用”的索引,不等于实际被选中。真正说话算数的是 key。
-
type = ALL且key = NULL→ 铁定全表扫描 -
type = range或ref且key有值 → 索引正在工作 -
key有值但rows接近总行数 → 索引“用了但没用好”,可能是低选择性或范围查询中断导致
type 值比 key 更早暴露问题
type 是执行计划里最敏感的信号灯。它反映访问方式的效率层级,从高到低大致是:const ≈ eq_ref > ref > range > index > ALL。一旦落到 ALL,基本可以断定索引失效或压根没参与。
-
type = ALL:逐行读取数据页,没走索引树,key必为NULL -
type = index:扫的是索引的全部叶子节点(覆盖索引时还行,否则仍要回表,性能差) -
type = range:走了索引范围扫描,但要注意后续列是否还能用(比如联合索引中a > 1 AND b = 2,b实际无法利用索引)
filtered 值过低暗示索引过滤效率差
filtered 表示 WHERE 条件对当前表的行过滤比例(百分比)。如果 filtered 明显偏低(比如 10.00),说明索引虽然被用了,但筛选能力很弱——可能因为查询条件没命中索引有效部分,或者数据分布极不均匀(如性别字段建索引)。
-
filtered = 100.00:条件能精准定位,索引用得干净利落 -
filtered < 10.00:大概率是索引列被函数包裹、隐式转换、或联合索引跳过了最左列 - 结合
rows看:若rows = 100000且filtered = 5.00,意味着 MySQL 预估要扫描 10 万行,只留下 5000 行,这已经接近全表扫描成本
联合索引下 key_len 异常短说明没用全
key_len 显示 MySQL 实际用到的索引字节数。对联合索引 (a,b,c),各字段长度已知时,key_len 能帮你判断用了几层:
- 只查
a = ?→key_len等于a的字节长度 - 查
a = ? AND b = ?→key_len应为a + b的长度 - 查
a = ? AND c = ?(跳过b)→key_len仍只含a,c不生效 -
key_len比预期小 → 后续字段没被索引覆盖,属于“部分失效”
真正容易被忽略的是:key_len 还受 NULL 属性和字符集影响(比如 VARCHAR 多 2 字节长度标识),所以比对时得确认定义,不能光靠直觉。


















