我不知道的 "SELECT"

接触过 SQL 的人都知道 SELECT,对 SELECT 的语法应该也非常熟悉。但是真的了解 SELECT 执行的底层原理嘛?SELECT 的执行顺序有是怎样的呢?

SELECT 的执行顺序

SELECT 查询时有两个顺序:

  1. 关键字的顺序, 而是该顺序是不能颠倒的:
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ...
  1. SELECT 语句的执行顺序:
FROM > WHERE > GROUP BY > HAVING > SELECT的字段 > DISTINCT > ORDER BY > LIMIT

比如有一个 SQL 语句,那么它的关键字顺序和执行顺序是下面这样的:

SELECT DISTINCT id, name, count(*) as num #顺序5
FROM person JOIN team ON person.team_id = team.team_id #顺序1
WHERE height > 1.80 #顺序2
GROUP BY person.team_id #顺序3
HAVING num > 2 #顺序4
ORDER BY num DESC #顺序6
LIMIT 2 #顺序7

其中,在执行 SQL 语句时,还有个聚合函数表达式计算,完整的执行顺序应该是这样:

  • FROM子句组装数据;
  • WHERE子句进行条件筛选;
  • GROUP BY分组;
  • 使用聚集函数进行计算;
  • HAVING筛选分组;
  • 计算所有的表达式;
  • SELECT 的字段;
  • ORDER BY排序;
  • LIMIT筛选

中间有两个过程是需要计算的:聚集函数 和 表达式。其余是关键字的执行顺序。

SELECT 语句在执行这些步骤的时候,每个步骤都会产生一个虚拟表,然后将这个虚拟表传入下一个步骤中作为输入。当然,这些步骤都是隐含在 SQL 的执行过程中的。

SELECT 的执行原理

通过上面的执行顺序可以知道,SELECT 是先执行 FROM 的,在这个阶段,如果是多张表联查,是会经历下面这几个步骤的:

  1. 首先先通过 CROSS JOIN 求笛卡尔积,相当于得到虚拟表 vt(virtual table)1-1;
  2. 通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2;
  3. 添加外部行。如果使用的是左连接、右链接或者全连接,就会涉及到外部行,也就是在虚拟表 vt1-2 的基础上增加外部行,得到虚拟表 vt1-3。

当然,如果操作的是两张以上的表,就会重复上面的步骤,直到所有表都被处理完为止。这个过程得到是的原始数据。

当拿到了查询数据表的原始数据,也就是最终的虚拟表 vt1,就可以在此基础上再进行 WHERE 阶段。在这个阶段中,会根据 vt1 表的结果进行筛选过滤,得到虚拟表 vt2。

然后进入第三步和第四步,也就是 GROUP 和 HAVING 阶段。在这个阶段中,实际上是在虚拟表 vt2 的基础上进行分组和分组过滤,得到中间的虚拟表 vt3 和 vt4。

完成了条件筛选部分之后,就可以筛选表中提取的字段,也就是进入到 SELECT 和 DISTINCT 阶段。

首先在 SELECT 阶段会提取想要的字段,然后在 DISTINCT 阶段过滤掉重复的行,分别得到中间的虚拟表 vt5-1 和 vt5-2。

当提取了想要的字段数据之后,就可以按照指定的字段进行排序,也就是 ORDER BY 阶段,得到虚拟表 vt6。

最后在 vt6 的基础上,取出指定行的记录,也就是 LIMIT 阶段,得到最终的结果,对应的是虚拟表 vt7。

当然,SELECT 语句,不一定存在所有的关键字,没有相应的关键字,相应的阶段就会省略。


说明:

内容来自极客时间专栏「SQL 必知必会

SQL 技术