索引失效主要因函数操作、LIKE通配符前置、联合索引跳过字段、范围查询后字段失效及隐式类型转换;需用EXPLAIN验证key_len和converted_for_comparison。
UPPER()、DATE() 等函数会直接失效MySQL 无法使用 B+ 树索引快速定位数据,因为索引存储的是原始列值,不是函数计算后的结果。优化器看到 WHERE UPPER(name) = 'ABC',就只能全表扫描——哪怕 name 上建了索引。
UPPER()、LOWER()、DATE()、YEAR()、SUBSTRING()、TRIM()、CONCAT()(左操作数为列时)WHERE create_time = '2025-01-01',而 crea
te_time 是 DATETIME 类型,MySQL 可能补上 CAST() 或内部转换,同样可能跳过索引CREATE INDEX idx_name ON t ((UPPER(name)))),但需显式创建,且查询条件必须完全匹配该函数表达式LIKE 以通配符开头导致索引无法做最左前缀匹配当写成 WHERE name LIKE '%abc' 或 WHERE name LIKE '%abc%',索引的有序性无法被利用,B+ 树没法从根节点往下高效过滤。
LIKE 'abc%' 这种前缀匹配才走索引(前提是 name 是联合索引最左列或独立索引)LIKE 'ab_c'(下划线单字符)仍可走索引,因为它是确定长度的前缀FULLTEXT)或引入 Elasticsearch,别硬扛假设建了联合索引 INDEX idx_user (status, city, age),以下查询中 age 字段实际不参与索引查找:
SELECT * FROM user WHERE status = 1 AND age = 25;
因为没提供 city,索引树只能定位到 status = 1 的所有块,之后在这些块里线性扫描 age,age 部分不生效。
status = 1 ✅,status = 1 AND city = 'BJ' ✅,status = 1 AND city = 'BJ' AND age > 20 ✅>、、BETWEEN)之后的字段也失效: WHERE status = 1 AND city > 'A' AND age = 25 → age 不走索引
EXPLAIN 看 key_len 和 Extra 字段当比较的两边类型不一致,MySQL 会尝试转换——但往往把索引列转成常量类型,导致索引失效。典型例子:
SELECT * FROM order WHERE order_no = 12345;
如果 order_no 是 VARCHAR 类型,这个查询会让 MySQL 把所有 order_no 值转成数字再比,于是放弃索引。
WHERE order_no = '12345'
WHERE id = CONCAT('1', '23')
EXPLAIN FORMAT=JSON 查 converted_for_comparison 字段索引失效不是玄学,本质是优化器判断“无法用索引结构加速定位”。每次加 WHERE 条件,都值得用 EXPLAIN 看一眼——尤其是上线前和慢查优化时。最容易被忽略的是隐式转换和联合索引的字段顺序,这两处出问题,连 EXPLAIN 的 key 字段都可能显示用了索引,但 key_len 却远小于预期。