news 2026/10/16 4:12:56

SQL执行顺序全解:从执行计划到性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL执行顺序全解:从执行计划到性能优化

1. 一条SQL语句的"执行剧本":先别急着背口诀

很多人一开始接触SQL执行顺序,第一反应就是去背那串口诀:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。背是背下来了,可真到写复杂查询的时候,照样懵。为什么?因为口诀背的是"逻辑执行顺序",而数据库真正跑起来的时候,是另一套"物理执行计划"——中间还藏着优化器这个"大管家"。

我在实际项目里见过太多类似的情况:某人写了个大JOIN,觉得"我WHERE里过滤了呀,怎么还这么慢",结果一看执行计划,WHERE条件被优化器推到了JOIN之后才生效。还有人在GROUP BY后面想用SELECT里的别名,报错之后一脸无辜:"不是先执行SELECT吗?"

所以这篇文章我不打算只给你口诀。我想带你从"数据库到底在干什么"的角度,把select、from、join、where、group by、having、order by、limit这条链路彻底捋清楚。搞懂它,你写SQL的时候就不只是"能跑",而是"知道它怎么跑、为什么这么跑、慢在哪、怎么改"。

这篇文章适合谁?刚入行的数据分析师、后端开发、运维,以及所有写过几条SQL但从来没看过执行计划的人。读完你会收获三样东西:一条能默写出来的执行链路、一套判断SQL性能瓶颈的思考框架,还有几个我从真实故障里总结出来的坑。

2. 从用户视角到数据库视角:两种顺序的"错位"

2.1 你写的顺序,不等于数据库做的顺序

先看一句最常见的 SQL:

SELECT department, COUNT(*) AS emp_count, AVG(salary) AS avg_salary FROM employees WHERE hire_date >= '2023-01-01' GROUP BY department HAVING COUNT(*) > 5 ORDER BY emp_count DESC LIMIT 10;

你写代码的时候,大脑的思考顺序是:先从 employees 表里"捞"数据 → 过滤掉 2023 年之前的 → 按部门分组 → 算人数和平均工资 → 过滤掉人数少于等于 5 的 → 按人数排序 → 取前 10 条。

这个思考过程完全合理,因为它符合人类的直觉:先选数据,再处理数据。但数据库不这么干。数据库的"逻辑执行顺序"是这样的:

  1. FROM:确定数据源,加载表
  2. JOIN:如果有连接,先做连接操作
  3. WHERE:对"源数据 + 连接结果"做行级过滤
  4. GROUP BY:把过滤后的数据分组
  5. HAVING:对分组后的结果做过滤
  6. SELECT:计算你要的列、聚合函数、表达式
  7. ORDER BY:排序
  8. LIMIT:截断

看出来了吗?**WHERE 跑在 GROUP BY 之前,而 SELECT 里的别名要到 ORDER BY 之前才算出来。**这就是为什么你在 WHERE 里不能用 SELECT 的别名,在 GROUP BY 里通常也不能用 SELECT 的别名(MySQL 某些版本放宽了,但语义上依然不推荐)——因为执行到 WHERE 的时候,SELECT 的投影计算压根还没发生。

2.2 为什么非要用这种"反直觉"的顺序?

数据库这么做,核心原因是为了"尽早减少数据量"。数据量越小,后续每一步的计算成本越低。如果先 SELECT 再 WHERE,那你得先把所有满足 FROM 的数据都做投影计算,生成一份可能很大的中间结果,再去过滤——纯粹是浪费。 WHERE 先跑,相当于在流水线的最前面就把废料扔掉了,后面的 GROUP BY、ORDER BY 处理的是"瘦身"之后的数据。

用一个生活化的类比:你要从一整车水果里挑出又大又红的苹果,称重后按重量排序。你不会先把所有水果都拍张照片(SELECT),再挑苹果(WHERE)——那太蠢了。你肯定是先挑苹果、再称重、再排序。SQL 的执行顺序本质上是同一套"先缩小规模,再精细处理"的思路。

3. 逐层拆解:每个关键字到底在干什么

3.1 FROM 和 JOIN:先搭好数据的"工作台"

FROM 是整个查询的地基。它决定了你要从哪张表、哪个视图、甚至哪个子查询里取数据。这一步在逻辑上会生成一个"虚拟表",这个虚拟表在物理上不一定真实存在,但它决定了后续所有操作的"数据边界"。

这里有个关键认知:如果查询里有多张表,FROM 阶段其实会先做一个"笛卡尔积"——也就是把每张表的每一行都和另一张表的每一行组合一遍。比如 A 表 100 行、B 表 200 行,笛卡尔积就是 20000 行。这显然很可怕,所以实际执行时数据库优化器会尽量用 JOIN 条件来避免真正的笛卡尔积,但逻辑上你要理解:JOIN 条件就是用来"约束"这个组合过程的。

JOIN 在逻辑执行顺序上和 FROM 是同一个阶段。你写FROM a JOIN b ON a.id = b.a_id,数据库会先把 a 和 b 通过连接条件组合成一张大虚拟表,然后再交给 WHERE。这也解释了

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 4:12:28

PYNQ开发入门:AXI_GPIO寄存器读写与Overlay加载实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 4:11:52

Fabric应用集成:fabric-gateway-java核心原理与生产实践

1. 为什么非得用 fabric-gateway-java?——从“手撕gRPC”到“开箱即用”的真实演进路径我第一次在某高校区块链实验室参与Fabric项目时,团队里三位开发者花了整整两周时间,硬是用原生gRPC Java SDK写完了一套链码调用逻辑。不是他们水平不够…

作者头像 李华
网站建设 2026/10/16 4:11:52

免费跑通Claude Code:三条实操路线与踩坑指南

做 AI 编程这块的,最近应该没人没听过Claude Code这个词。终端里的 AI 结对编程,一句话描述需求,它自己读代码、搜文件、跑测试、改 bug,那种“手不离键盘”的体验确实很上瘾。可真正上手时,第一道墙不是命令行的学习成…

作者头像 李华
网站建设 2026/10/16 4:11:33

SQL日期函数DATEDIFF详解:从边界条件到性能优化实战

DATEDIFF 应该是 SQL 里最常用也最容易被轻视的函数之一。很多开发者在项目初期用它算个日期差,感觉简单到不需要看文档——两个日期一减,天数出来了,完事。但等你真正处理过跨年数据、排查过慢查询、或者接过一个用了 Oracle 和 PostgreSQL …

作者头像 李华
网站建设 2026/10/16 4:10:54

Vue3低代码大屏可视化搭建系统源码(可二次开发)

简介:这是一套基于Vue.js开发的大屏可视化搭建系统源码,面向前端开发者、数据可视化工程师及中高级Vue学习者,解决企业级大屏项目中组件复用难、数据联动弱、定制扩展成本高等核心问题。资源包共1131个文件,涵盖208个Vue单文件组件…

作者头像 李华
网站建设 2026/10/16 4:10:52

达梦数据库阻塞排查:用sqllog还原锁等待现场

用达梦数据库跑业务的人,应该都有过这种经历:业务群里突然有人喊“系统卡死了”,登录数据库一看,V$LOCK里躺着好几条记录,某个会话的锁一直被另一个会话占着。常规操作是查系统视图,找到持锁会话&#xff0…

作者头像 李华