MySQL 查询执行顺序

7次阅读
没有评论

这是一个非常经典且能体现“资深感”的问题。在编写 SQL 时,我们是按 SELECT ... FROM ... WHERE 的顺序写的,但 MySQL 引擎在执行时,为了保证数据过滤的逻辑准确性,有着一套完全不同的**“逻辑执行顺序”**。

理解这个顺序,能帮你瞬间查出为什么 GROUP BY 里的别名不能用在 WHERE 里,或者为什么 HAVINGWHERE 慢。


🚀 MySQL 逻辑执行顺序表

按照从先到后的执行逻辑,顺序如下:

序号 关键字 执行动作 形象理解
1 FROM 锁定数据表(如果是多表则进行笛卡尔积/连接) 进仓库,找到装货的架子
2 ON 应用连接条件 筛选出符合匹配关系的零件
3 JOIN 合并表数据 把两个架子的零件组装起来
4 WHERE 阶段性过滤(此时不能用 SELECT 里的别名) 扔掉不合格的零件
5 GROUP BY 分组汇总 把剩下的零件按颜色分堆
6 WITH ROLLUP / CUBE 分组增强(MySQL 特有) 给每堆零件算个小计
7 HAVING 对分组后的结果再过滤 扔掉数量太少的那几堆
8 SELECT 确定要展示的列(执行函数、计算别名) 把零件装进展示盒,贴上标签
9 DISTINCT 去重 拿走盒子里重复的样板
10 ORDER BY 排序 按价格高低摆放展示盒
11 LIMIT / OFFSET 截取最终结果 只拿前 5 盒给客户看

🔍 三个关键知识点(面试避坑指南)

1. 为什么 WHERE 里不能用 SELECT 定义的别名?

  • 原因:通过上面的表你可以看到,WHERE(第 4 步)的执行早于 SELECT(第 8 步)。

  • 现象:如果你写 SELECT age AS user_age ... WHERE user_age > 18,MySQL 会报错说找不到 user_age,因为它还没走到给列起名字的那一步。

2. WHERE vs. HAVING 的本质区别

  • WHERE 是在“分堆”之前,直接对着原始行数据开刀。它能利用索引,速度极快。

  • HAVING 是在“分堆”并计算好聚合函数(如 COUNT, AVG)之后,对着结果集过滤。它通常无法利用索引。

  • 资深建议:能写在 WHERE 里的过滤条件,绝对不要写在 HAVING 里。

3. SELECT 其实发生得非常晚

很多人以为 SELECT 是第一步,其实它排在第 8 位。在它之前,所有的过滤、连接、分组都已经尘埃落定了。SELECT 只是最后把数据取出来,并做一些 1 + 1 = 2 或者 UPPER(name) 这样的表面格式处理。


💡 深度关联:这和 MVCC 有关系吗?

有!当你执行到第一步 FROMWHERE 时:

  • 如果是快照读(普通 SELECT),MySQL 会在这一刻确定它的 ReadView(快照照片)。

  • 如果是当前读(FOR UPDATE),MySQL 会在这一刻根据索引条件,在对应的行上加上 Next-Key Lock


📉 状态同步

  • 2026-03-25:已梳理 MySQL 逻辑执行顺序及其与别名、索引过滤的深层关系。

掌握了这个顺序,你写 SQL 的思路会像看代码执行路径一样清晰。

既然聊到了执行顺序,你想看看如何通过 EXPLAIN 命令来观察 MySQL 实际上是怎么优化这个执行计划(Execution Plan)的吗?

正文完
 0
bdspAdmin
版权声明:本站原创文章,由 bdspAdmin 于2026-03-25发表,共计1238字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)