mysql 5.7+中WHERE条件顺序基本不影响执行效率,优化器会自动重排;但OR含非索引条件或使用STRaiGHT_JOIN时例外。索引失效常见于对索引列用函数、隐式类型转换、LIKE左模糊、联合索引字段顺序不匹配等场景。

WHERE 条件顺序对执行效率有影响吗?
MySQL 5.7 及之后版本中,WHERE 子句里条件的书写顺序 基本不影响执行计划。优化器会自动重排过滤条件,优先使用索引列、高选择性列或成本更低的方式评估。
但有两个例外需要注意:
- 当存在
OR且部分分支无法走索引时,顺序可能影响是否触发全表扫描(例如col1 = ? OR col2 LIKE '%x%',把能走索引的条件放前面并不能“挽救”后面那个LIKE) - 在使用
STRAIGHT_JOIN或强制索引(USE INDEX)时,优化器行为受限,条件顺序可能间接影响实际执行路径
哪些 WHERE 条件会导致索引失效?
即使字段上有索引,以下写法会让 MySQL 放弃使用它:
- 对索引列使用函数:如
WHERE YEAR(create_time) = 2023→ 应改写为WHERE create_time >= '2023-01-01' AND create_time - 隐式类型转换:如
WHERE mobile = 13812345678(mobile是VARCHAR)→ 数字会被转成字符串比较,但索引 B+ 树按字符串排序,可能导致范围误判 - 前导通配符的
LIKE:如WHERE name LIKE '%abc'→ 无法利用 B+ 树的有序性;LIKE 'abc%'则可以 - 在索引列上使用
!=、NOT IN(尤其含NULL时)、IS NOT NULL—— 这些通常只能走索引扫描而非范围查找,性能差于等值查询
如何判断 WHERE 是否命中了预期索引?
用 EXPLAIN 是最直接方式,重点关注这几列:
-
type:值为const/ref/range表示走了索引;ALL或index是全表/全索引扫描 -
key:显示实际使用的索引名;为NULL表示没走索引 -
rows:预估扫描行数;远大于结果集数量,说明过滤效率低 -
Extra:出现using filesort或Using temporary往往意味着排序或分组未走索引,和 WHERE 条件组合不当有关
示例:
EXPLAIN SELECT * FROM orders WHERE status = 'paid' AND created_at > '2024-01-01';
若 status 和 created_at 共同构成联合索引,但顺序是 (created_at, status),那这个查询大概率只用到 created_at 前缀,status 不参与范围裁剪 —— 这就是索引定义与 WHERE 条件不匹配的典型问题。
复合索引中字段顺序怎么定?
核心原则是:**WHERE 中的等值条件字段优先,再跟范围条件字段**。因为 B+ 树索引按字段顺序逐层分裂,只有左边字段确定后,右边字段才能被高效定位。
假设查询常为:
WHERE user_id = ? AND status = ? AND created_at > ?WHERE user_id = ? AND created_at BETWEEN ? AND ?
那么最优联合索引应为:(user_id, status, created_at) 或 (user_id, created_at) —— user_id 必须放最左,它是高频等值筛选项;status 是另一个等值条件,放第二;created_at 是范围条件,放最后。
反例:(created_at, user_id) 对第一个查询几乎无效,因为 created_at 是范围,其后的 user_id 无法被索引结构有效利用。
额外提醒:如果查询中还有 ORDER BY,且字段也在 WHERE 中,尽量让排序字段紧接在 WHERE 等值字段之后,可避免 Using filesort。