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。
