mysql中WHERE子句条件的优化与执行

来源:这里教程网 时间:2026-02-28 20:47:35 作者:

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

相关推荐