原文:https://zhuanlan.zhihu.com/p/77847158
主要是SQL的书写顺序和执行顺序
执行顺序
(8) SELECT (9)DISTINCT<Select_list>
(1) FROM <left_table> (3) <join_type>JOIN<right_table>
(2) ON<join_condition>
(4) WHERE<where_condition>
(5) GROUP BY<group_by_list>
(6) WITH {CUBE|ROLLUP}
(7) HAVING<having_condtion>
(10) ORDER BY<order_by_list>
(11) LIMIT<limit_number>
我们可以看出,SELECT子句是必选的,其它子句如WHERE子句、GROUP BY子句等是可选的。
一个SELECT语句中,子句的顺序是固定的。必须严格按照上述的顺序书写。
所有的查询语句都是从FROM开始执行的,在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入。
- 先对FROM子句中的两个表执行一个笛卡尔乘,此时生成虚拟表 virtual table 1(选择相对小的表做基础表)
- 然后是应用ON条件筛选器,将ON中的逻辑表达式将应用到 virtual table 1中的各个行,筛选出满足ON中的逻辑表达式的行,生成虚拟表 virtual table 2
- 根据连接方式进行进一步的操作。如果是OUTER JOIN,那么这一步就将添加外部行
- LEFT OUTER JOIN就把左表在第二步中筛选掉的行添加进来
- RIGHT OUTER JOIN就将右表在第二步中筛选掉的行添加进来 这样生成虚拟表 virtual table 3
如果 FROM子句中的表数目大于2,那么就将virtual table 3和第三个表连接从而计算笛卡尔积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表virtual table 3
- 应用WHERE筛选器,对上一步生产的virtual table 3用WHERE筛选器筛选,生成虚拟表virtual table 4
在这有个比较重要的细节需要提一下,如果我们有一个condition需要去筛选,应该在在ON条件筛选器还是用WHERE筛选器指定condition逻辑表达式呢?
ON和WHERE的最大区别在于,如果在ON应用逻辑表达式那么在第三步OUTER JOIN中还可以把移除的行再次添加回来,而WHERE的移除的不可挽回的 - GROUP BY子句将具有相同属性的row组合成为一组,得到虚拟表virtual table 5
如果应用了GROUP BY,那么后面的所有步骤都只能得到的virtual table 5的列或者是聚合函数,并且分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,这一点请牢记。 - 应用CUBE或者ROLLUP选项,为virtual table 5生成超组,生成virtual table 6. 这个暂时还没了解,先放到这里吧。
- 应用HAVING筛选器,生成virtual table 7
HAVING筛选器是唯一一个用来筛选组的筛选器 - 处理SELECT子句。将virtual table 7中的并且在Select_list中的列筛选出来,生成virtual table 8
- 应用DISTINCT子句,virtual table 8中移除相同的行,生成virtual table 9
事实上如果应用了GROUP BY子句,那么DISTINCT是多余的,原因同样在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,那么所以的记录都将是不相同的。 - 应用ORDER BY子句。按照order_by_condition排序virtual table 10,此时返回的一个游标,而不是虚拟表。SQL是基于集合的,集合不会预先对行进行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使用ORDER BY子句查询不能应用于表达式。