key为null说明未走索引;需结合type(all为全表扫描)、rows(扫描行数是否远小于总数)判断,联合索引须满足最左前缀,函数、隐式转换、not、前导%等均会导致索引失效。

先看EXPLAIN结果里key字段是不是NULL
这是最直接的判断依据。只要key列显示NULL,就说明这条查询压根没用上索引;如果possible_keys有值但key是NULL,说明优化器评估后主动放弃了所有可用索引。
常见干扰项:type为ALL或index时,基本等于没走有效索引;type是range/ref/const才表示走了索引扫描。
- 别只盯着
possible_keys——它只是“候选”,不是“当选” -
Extra里出现Using filesort或Using temporary不直接代表索引失效,但常伴随低效执行路径 - 如果表很小(比如几百行),优化器可能认为全表扫描比索引+回表更快,
key也会是NULL
检查WHERE条件是否对索引列做了函数或计算
只要在索引列上套了函数、加减乘除、字符串拼接,索引就大概率失效。MySQL无法把函数结果和B+树里存的原始值做有序匹配。
典型例子:
-
WHERE YEAR(create_time) = 2023→ 改成WHERE create_time >= '2023-01-01' AND create_time -
WHERE price * 1.1 > 100→ 改成WHERE price > 90.91(注意精度) -
WHERE UPPER(name) = 'ABC'→ 改成WHERE name = 'abc'(配合case-insensitive collation)
注意:MySQL 8.0+支持函数索引,但必须显式创建,比如CREATE INDEX idx_year ON t (YEAR(create_time)),否则默认不生效。
确认联合索引是否违反最左前缀原则
联合索引(a,b,c)只对以下条件生效:WHERE a = ?、WHERE a = ? AND b = ?、WHERE a = ? AND b = ? AND c = ?。跳过a或中间断开,索引就废了。
容易被忽略的细节:
-
WHERE b = ? AND c = ?→ 完全不走索引 -
WHERE a = ? AND c = ?→ 只能用上a,c部分变成过滤(Extra里会写Using where) -
WHERE a > ? AND b = ?→b索引部分失效,因为范围查询后无法继续用B+树做等值跳转
如果高频查b,别硬凑(a,b,c),考虑单独建(b)索引,或调整顺序为(b,a,c)。
排查隐式类型转换和LIKE前导通配符
这两类问题不会报错,但会让索引静默失效,特别难察觉。
隐式转换典型场景:
- 索引列是
VARCHAR,但传入数字:WHERE user_id = 123→ MySQL自动转成字符串比较,触发全表扫描 - 索引列是
INT,但传入带空格字符串:WHERE id = ' 123 '→ 同样触发转换
LIKE问题更隐蔽:
-
WHERE name LIKE '%张'或WHERE name LIKE '%张%'→ 前导%让B+树无法定位起始位置 -
WHERE name LIKE '张%'→ 可用索引,且效率接近等值查询
真正麻烦的是参数化查询里拼接的%——业务代码里name LIKE CONCAT('%', ?, '%')看着没问题,实际就是全扫。
复杂点在于:同一个SQL,在不同数据分布下可能有时走索引、有时不走。比如state只有5个取值,查WHERE state = 'CA'若命中80%行,优化器大概率放弃索引。这种时候EXPLAIN看到的key是NULL,但不是写法错,是数据特征决定的。











