vlambda博客
学习文章列表

你不会以为SQL查询是从SELECT开始的吧?来来来,千万别打脸。

使用 group by 进行分组操作后,不能在 where 中使用聚合方法的别名。于是我又想到了另一个问题:SQL 查询的执行顺序是怎样的?很多 SQL 查询都是以 SELECT 开始的,自己已经写了很多 SQL 查询了,有一些还很复杂。但是我仍然很难确切地说出它的顺序是怎样的。

SQL 查询的执行顺序

于是我研究了一下,发现顺序大概是这样的。SELECT 并不是最先执行的,而是在第五个。

图片来源于网络

这张图回答了以下这些问题

这张图与 SQL 查询的语义有关,让你知道一个查询会返回什么,并回答了以下这些问题:

  1. 可以在 GRROUP BY 之后使用 WHERE 吗?(不行,WHERE 是在 GROUP BY 之前!)
  2. 可以对窗口函数返回的结果进行过滤吗?(不行,窗口函数是 SELECT 语句里,而 SELECT 是在 WHERE 和 GROUP BY 之后)
  3. 可以基于 GROUP BY 里的东西进行 ORDER BY 吗?(可以,ORDER BY 基本上是在最后执行的,所以可以基于任何东西进行 ORDER BY)
  4. LIMIT 是在什么时候执行?(在最后!)

在实际的数据库引擎中,并不一定严格按照这个顺序执行 SQL 查询,因为为了更快地执行查询,数据库引擎会做一些优化,这样就有可能改变子句的执行顺序,所以在涉及查询性能或者与索引有关的东西时,这张图就不适用了。

但是如果你想要知道一个查询语句是否合法,或者想要知道一个查询语句会返回什么,可以参考这张图。这个就是我们了解 SQL 子句执行顺序的意义。

我们就以下面的查询 SQL 为例,讲解一下整个 SQL 的执行顺序吧。

(6) SELECT [DISTINCT | ALL] COL1, AGE, GENDER
(1FROM T1 JOIN T2
(2ON T1.AID = T2.BID
(3WHERE T1.AGE > 18 AND T2.GENDER = 'BOY'
(4GROUP BY COL1
(5HAVING AVG(AGE) >= 22
(7UNION ALL
      ...
(8ORDER BY COL1 DESC, COL2 ASC
(9OFFSET 0 LIMIT 20

▼关注回复【面试】获取面试资料▼

步骤1:获取数据(From, Join)

首先,执行(1)From 和 Join 子句,对2张表进行组合,形成此次查询所需要的记录集合。

FROM T1 JOIN T2

步骤2:关联过滤(On)

From 和 Join 子句执行之后,处理器会根据 On 指定的条件从记录集合中挑出符合条件的记录:

ON T1.AID = T2.BID

步骤3:记录过滤(Where)

拿到了记录集合之后,开始执行 Where 子句。使用指定的条件过滤记录集合,如果计算结果不为 true,就会从记录集合中移除。

WHERE T1.AGE > 18 AND T2.GENDER = 'BOY'

步骤4:分组(Group by)

执行 Group by 子句,对记录集合分组,把 COL1 相同的放到一组。

GROUP BY COL1

步骤5:分组过滤(Having)

having中可以是普通条件的筛选,也能是聚合函数。而where只能是普通函数,一般情况下,有having可以不写where,把where的筛选放在having里,SQL语句看上去更丝滑。

HAVING AVG(AGE) >= 22

步骤6:筛选字段(Select)

select 子句是使用最多,也最容易理解的子句,从之前各个子句的结果集中,筛选出所需要的字段,同时可以做一些其它比如去重等操作。

SELECT [DISTINCT | ALL] COL1, AGE, GENDER

步骤7:合并(UNION ALL & UNION)

UNION ALL 对两个结果集进行并集操作,包括重复行,不进行排序;如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。如果想把结果集去重,可以使用 UNION。

步骤8:排序(ORDER BY)

ORDER BY 子句的操作就是对结果集排序,按字段先后进行排序,比如下列是COL1先做降序,如果相同的情况下按COL2进行升序排序。

ORDER BY COL1 DESC, COL2 ASC

步骤9:分页(OFFSET & LIMIT)

使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不如分页显示,每次显示100条。

要实现分页功能,实际上就是从结果集中显示第1~100条记录作为第1页,显示第101~200条记录作为第2页,以此类推。

OFFSET 0 LIMIT 100