SQL查询解析全流程:从FROM到ORDER BY的虚拟表演变

周叙
周叙
发布时间:2026-10-14 | 2人浏览过
原创

许多开发者常困惑于SQL关键字的执行顺序,误以为SELECT最先执行。实际上,SQL引擎遵循严格的逻辑解析顺序。本文详细梳理了从FROM到ORDER BY的完整解析过程,通过虚拟表的转换揭示了数据处理机制,帮助理解复杂的JOIN过滤、聚合限制及性能优化原理。

核心结论:SQL解析的真实顺序

SQL语句并非按照书写顺序执行,而是由数据库引擎按以下逻辑顺序进行处理:

  1. FROM - 确定数据来源
  2. WHERE - 行级过滤
  3. GROUP BY - 数据分组
  4. HAVING - 组级过滤
  5. SELECT - 列选择与表达式计算
  6. ORDER BY - 结果排序

这一顺序决定了哪些数据可用,以及可以使用哪些聚合函数。下面将通过具体的“客户-订单”案例逐步演示。

Step 1:FROM子句与虚拟表VT1的生成

FROM子句定义了数据源。如果涉及多表连接,数据库会按从左到右的顺序逐步构建中间结果集(虚拟表)。

第1步:执行笛卡尔积 (Step 1-J1)

对于JOIN操作,首先进行的是笛卡尔积(CROSS JOIN)。即使使用了LEFT OUTER JOIN,底层逻辑依然是先产生所有可能的组合,再进行过滤和保留。

  • 输入:Customers表(4行) × Orders表(7行)
  • 操作:将所有可能的行组合拼接
  • 输出:生成虚拟表 VT1-J1(共28行,包含所有列)

第2步:应用ON过滤 (Step 1-J2)

在VT1-J1的基础上,应用JOIN条件进行过滤。只有满足 C.customerid = O.customerid 的行才会被保留。

  • 操作:筛选出符合连接条件的行
  • 输出:生成虚拟表 VT1-J2(匹配成功的行)

第3步:添加外部行 (Step 1-J3)

仅在外连接(LEFT/RIGHT/FULL)时发生。将主表(如LEFT JOIN的左表)中未匹配上的行,以NULL填充右侧字段,追加到VT1-J2中。

  • 目的:确保主表数据不丢失
  • 输出:生成虚拟表 VT1-J3,此时包含了匹配行和保留的外部行

Step 2:WHERE子句与虚拟表VT2

WHERE用于对VT1-J3生成的数据进行行级过滤。注意,此时数据尚未分组,因此不能使用聚合函数(如COUNT、MAX)。

  • 示例条件:WHERE C.city = 'Madrid'
  • 关键点:若希望过滤掉非Madrid的客户,必须放在WHERE而非ON中。若放ON中,这些客户会在Step 1-J3作为外部行重新被加回。
  • 输出:生成虚拟表 VT2,仅包含Madrid市的客户及其相关订单信息

Step 3:GROUP BY与虚拟表VT3

将VT2中的数据按照指定列进行分组,每组在后续步骤中将被视为单行处理。

  • 操作:按 C.customerid 分组
  • 规则:出现在GROUP BY后的子句(如SELECT、HAVING)只能引用分组列或聚合函数,否则报错
  • 输出:生成虚拟表 VT3,结构上增加了分组标识

Step 4:HAVING与虚拟表VT4

HAVING用于对分组后的数据进行过滤,类似于WHERE但作用于聚合后的组。

  • 示例条件:HAVING COUNT(O.orderid) < 3
  • 细节:此处使用 O.orderid 而非 *,因为 COUNT(*) 会统计NULL值,而 COUNT(列名) 忽略NULL。由于外连接有NULL值,二者结果不同。
  • 输出:生成虚拟表 VT4,仅保留订单数少于3的客户组

Step 5:SELECT与虚拟表VT5

尽管SELECT写在最前,但它实际在第五步执行。它负责选取最终的展示列并计算表达式。

第5.1步:计算表达式

  • 操作:解析 C.customerid 和 COUNT(O.orderid) AS numorders
  • 约束:SELECT中定义的别名(如 numorders)在当前步骤不可用,但在后续ORDER BY中可用
  • 输出:生成虚拟表 VT5-1

第5.2步:应用DISTINCT

如果SQL中包含DISTINCT,此时去除重复行,生成 VT5-2。本例未使用,故跳过。

第5.3步:应用TOP

T-SQL特有,基于ORDER BY的结果截取前N行。本例未使用,故跳过。

Step 6:ORDER BY与游标VC6

最后一步是对结果集进行排序。这是唯一允许使用SELECT别名的地方。

  • 操作:根据 numorders 升序排列
  • 结果:生成最终返回给用户的游标对象 VC6。需注意的是,SQL标准中集合是无序的,ORDER BY产生的是一种序列化的视图。
image

总结与最佳实践

理解SQL解析顺序有助于写出正确的查询:

  1. ON vs WHERE:内连接无区别;外连接中,ON在添加外部行前过滤,WHERE在后。想过滤主表数据请用WHERE。
  2. 聚合位置:行过滤用WHERE,组过滤用HAVING。
  3. 别名作用域:SELECT别名可在ORDER BY中使用,但不能在WHERE/HAVING中提前引用。

以上就是SQL语句各个关键字的详细解析过程,更多关于数据库原理与优化的资料请关注本站其它相关文章!

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表