如何在where条件中使用索引_mysql条件优化

8次阅读

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

如何在where条件中使用索引_mysql条件优化

在 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 filesortUsing temporary 常意味着排序/分组未走索引,需结合 ORDER BY 或 GROUP BY 优化

执行后若发现没走索引,先看 warning:SHOW WARNINGS,有时会提示“Cannot use ref access on index … due to type or charset mismatch”。

text=ZqhQzanResources