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

1次阅读

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

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

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 = 13812345678mobileVARCHAR)→ 数字会被转成字符串比较,但索引 B+ 树按字符串排序,可能导致范围误判
  • 前导通配符的 LIKE:如 WHERE name LIKE '%abc' → 无法利用 B+ 树的有序性;LIKE 'abc%' 则可以
  • 在索引列上使用 !=NOT IN(尤其含 NULL 时)、IS NOT NULL —— 这些通常只能走索引扫描而非范围查找,性能差于等值查询

如何判断 WHERE 是否命中了预期索引?

EXPLAIN 是最直接方式,重点关注这几列:

  • type:值为 const / ref / range 表示走了索引;ALLindex 是全表/全索引扫描
  • key:显示实际使用的索引名;为 NULL 表示没走索引
  • rows:预估扫描行数;远大于结果集数量,说明过滤效率低
  • Extra:出现 using filesortUsing temporary 往往意味着排序或分组未走索引,和 WHERE 条件组合不当有关

示例:

EXPLAIN SELECT * FROM orders WHERE status = 'paid' AND created_at > '2024-01-01';

statuscreated_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

text=ZqhQzanResources