SQL语句执行顺序
graph TB;
id0(FROM)-->id1(JOIN);
id1-->id2(ON);
id2-->id3(WHERE);
id3-->id4(GROUP BY);
id4-->id5(AVG,SUM,...);
id5-->id6(HAVING);
id6-->id7(SELECT);
id7-->id8(DISTINCT);
id8-->id9(ORDER BY);
- 所有的查询语句都是从
FROM开始执行的 - 在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,该虚拟表将作为下一个执行步骤的输入
- 执行
FROM子句,生成虚拟表vt1(选择相对小的表做基础表) - 应用
ON筛选器,ON中的逻辑表达式将应用到vt1中的各个行,筛选出符合条件的行,生成虚拟表vt2 - 执行
JOIN语句,添加
- 如果是
OUTER JOIN,则添加外部行 - 如果是
LEFT OUTER JOIN,则添加左表在第二步中过滤后得到的行 - 如果是
RIGHT OUTER JOIN,则添加右表在第二步中过滤后得到的行
生成虚拟表vt3
4. 如果FROM子句中的表数目多于2个表,则将vt3和第三个表重复13的步骤,得到的虚拟表记为`vt3`;将`vt3`和第四个表重复13的步骤,得到的虚拟表记为vt3;……直到处理完FROM子句中的所有的表
5. 对虚拟表vt3应用WHERE筛选器,生成虚拟表vt4
6. GROUP BY col_name子句按col_name列聚合(col_name相同值为一组),得到虚拟vt5表
- 如果应用了
GROUP BY,则后面的步骤都只能得到vt5表的列或使用关于vt5表的列的聚合函数(COUNT,SUM,AVG等) GROUP BY将列中唯一的值分成一组,同时只为每一组返回一行记录
- Oracle特有:应用
CUBE或ROLLUP选项,为vt5生成超组,得到虚拟表vt6 - 应用
HAVING筛选器,生成虚拟表vt7
HAVING是第一个也是唯一一个应用到已分组数据的筛选器
- 处理
SELECT子句,将虚拟表vt7中出现的列筛选出来,生成虚拟表vt8 - 应用
DISTINCT子句,移除vt8中相同的行,生成虚拟表vt9
- 如果应用了
GROUP BY子句,则DISTINCT子句是多余的 GROUP BY的效率比DISTINCT高
- 应用
ORDER BY子句,返回一个游标,而不是虚拟表
- 是第一个也是唯一一个可以使用
SELECT列表中别名的步骤
- 应用
TOP,将返回结果给请求者
以MySQL为例,写的SQL语句顺序为
1 | SELECT ... |
执行顺序
1 | FROM ... JOIN ... ON ... |
Oracle
Oracle中,在进行多列分组统计时,如果直接使用GROUP BY子句指定分组列,则只能生成基于所有分组列的统计结果。
如果在GROUP BY子句中使用ROLLUP语句或CUBE语句,除了生成基于所有指定列的分组统计外,还可以生成基于指定列不同子集的统计结果。
CUBE
使用CUBE选项,除了生成基于所有指定列的分组统计外,还对指定分组列的所有子集进行统计
1 | GROUP BY CUBE(A,B,C) |
形成的统计包括以下内容:
GROUP BY:不基于任何列的整个查询结果的统计GROUP BY A:基于A列的分组统计GROUP BY B:基于B列的分组统计GROUP BY C:基于C列的分组统计GROUP BY A,B:基于A、B两列的分组统计GROUP BY A,C:基于A、C两列的分组统计GROUP BY B,C:基于B、C两列的分组统计GROUP BY A,B,C:基于A、B、C三列的分组统计
ROLLUP
使用ROLLUP选项,除了生成基于所有指定列的分组统计外,还对指定的分组列从左开始的每个子集进行统计。
1 | GROUP BY ROLLUP(A,B,C) |
形成的统计包括以下内容:
GROUP BY:不基于任何列的整个查询结果的统计GROUP BY A:基于A列的分组统计GROUP BY A,B:基于A、B两列的分组统计GROUP BY A,B,C:基于A、B、C三列的分组统计