MySQL中WHERE条件能否走索引取决于最左前缀原则、是否发生隐式转换、操作符是否支持范围扫描;联合索引需从最左列连续匹配,避免函数、非SARGable表达式及类型/字符集不一致,务必用EXPLAIN验证。

在 MySQL 中,WHERE 条件能否走索引,不取决于写法多“标准”,而取决于是否符合索引的最左前缀原则、字段是否发生隐式转换、以及操作符是否支持范围扫描。很多查询明明建了索引却没用上,问题往往出在条件写法细节上。
确保满足最左前缀原则
联合索引(如 INDEX idx_name_age_city (name, age, city))只有从最左边列开始连续匹配,才能有效利用索引:
- ✅
WHERE name = '张三'→ 走索引 - ✅
WHERE name = '张三' AND age > 25→ 走索引(name 精确 + age 范围) - ✅
WHERE name = '张三' AND age = 28 AND city = '北京'→ 全部走索引 - ❌
WHERE age = 28→ 不走索引(跳过最左列 name) - ❌
WHERE city = '北京'→ 不走索引(未包含 name 和 age) - ⚠️
WHERE name LIKE '%三'→ 不走索引(左模糊,无法定位起始位置) - ✅
WHERE name LIKE '张%'→ 可走索引(右模糊或全匹配可利用 B+ 树结构)
避免隐式类型/字符集转换
当 WHERE 字段与条件值类型不一致,或字段定义与传入值字符集不同,MySQL 会自动转换,导致索引失效:
- ❌
WHERE user_id = '123'(user_id 是 INT)→ MySQL 把字符串转为数字,但可能放弃索引(尤其在老版本) - ✅ 应写成
WHERE user_id = 123 - ❌
WHERE mobile = 13812345678(mobile 是 VARCHAR)→ 数字常量触发隐式转换,可能全表扫描 - ✅ 应写成
WHERE mobile = '13812345678' - ⚠️ 若字段是 utf8mb4,但连接字符集是 latin1,也可能触发转换失效索引(可通过
SHOW VARIABLES LIKE 'character_set%'检查)
慎用非SARGable表达式
SARGable(Search ARGument Able)指能被数据库引擎直接用于索引查找的条件。对字段使用函数、运算或 NOT,通常会让索引失效:
- ❌
WHERE YEAR(create_time) = 2023→ 函数作用于字段,无法走索引 - ✅ 改为
WHERE create_time >= '2023-01-01' AND create_time - ❌
WHERE price * 1.1 > 100→ 表达式计算在字段上 - ✅ 改为
WHERE price > 100 / 1.1 - ❌
WHERE status != 1→ 非等值且非范围,多数情况下不走索引(除非覆盖且区分度极高) - ✅ 如需查少数状态,优先用
IN或正向条件(如status IN (2,3))
用 EXPLAIN 验证实际执行路径
别猜,要查。在 SQL 前加 EXPLAIN,重点关注这几列:
-
type:至少达到
range(范围扫描)或更好(ref/eq_ref)才算有效走索引;ALL是全表扫描 -
key:显示实际使用的索引名;为
NULL表示没走索引 - rows:预估扫描行数,越小越好;远大于结果集说明索引效率低
-
Extra:出现
Using filesort或Using temporary常意味着排序/分组未走索引,需结合 ORDER BY 或 GROUP BY 优化
执行后若发现没走索引,先看 warning:SHOW WARNINGS,有时会提示“Cannot use ref access on index … due to type or charset mismatch”。










