2018-10-30 孙小北

SQL语句执行顺序及优化

养浩然之气,做博学之人

SQL 不同于与其他编程语言的最明显特征是处理代码的顺序。在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管SELECT语句第一个出现,但是几乎总是最后被处理。每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入。这些虚拟表对调用者(客户端应用程序或者外部查询)不可用。只是最后一步生成的表才会返回给调用者。

一、查询语句书写顺序

select -->from -- >where --> group by -->having -->order by

其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 与sql语句的书写顺序并不是一样的。

二、查询语句执行顺序

from (-->on)-->where -->group by (-->with) -->having -->select -->order by

SELECT DISTINCT top_specification select_list
    FROM left_table join_type JOIN right_table  ON join_condition
    WHERE where_condition
    GROUP BY group_by_list
    WITH {cube | rollup}
    HAVING having_condition
    ORDER BY order_by_list

(1) FROM left_table
(2) ON join_condition
(3) join_type JOIN right_table 
(4) WHERE where_condition
(5) GROUP BY group_by_list
(6) WITH {cube | rollup}
(7) HAVING having_condition
(8) SELECT 
(9) DISTINCT
(10) ORDER BY order_by_list
(11) top_specification select_list


1. FROM:对FROM子句中前两个表执行笛卡尔积生成虚拟表vt1
  2. ON: 对vt1表应用ON筛选器只有满足 join_condition 为真的行才被插入vt2
  3. OUTER(join):如果指定了 OUTER JOIN保留表(preserved table)中未找到的行将行作为外部行添加到vt2,生成t3,如果from包含两个以上表,则对上一个联结生成的结果表和下一个表重复执行步骤和步骤直接结束。
  4. WHERE:对vt3应用 WHERE 筛选器只有使 where_condition 为true的行才被插入vt4
  5. GROUP BY:按GROUP BY子句中的列列表对vt4中的行分组生成vt5
  6. CUBE|ROLLUP:把超组(supergroups)插入vt6,生成vt6
  7. HAVING:对vt6应用HAVING筛选器只有使 having_condition 为true的组才插入vt7
  8. SELECT:处理select列表产生vt8
  9. DISTINCT:将重复的行从vt8中去除产生vt9
  10. ORDER BY:将vt9的行按order by子句中的列列表排序生成一个游标vc10
  11. TOP:从vc10的开始处选择指定数量或比例的行生成vt11 并返回调用者

注意:from后面的表关联,是自右向左解析的 ,而where条件的解析顺序是自下而上的。

三、标准的 SQL 的解析顺序

1、from子句组装来自不同数据源的数据; 
  2、where子句基于指定的条件对记录行进行筛选; 
  3、group by子句将数据划分为多个分组; 
  4、使用聚集函数进行计算; 
  5、使用having子句筛选分组; 
  6、计算所有的表达式; 
  7、使用order by对结果集进行排序。

四、根据执行顺序对SQL进行优化

1.from 子句--执行顺序为从后往前、从右到左

表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后)

SQL优化思路:在FROM 子句中包含多个表的情况下,你必须选择记录最少的表作为基础表(驱动表)。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表。多表连接时,使用表的别名并把别名前缀于每个Column上,可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

2.where子句--执行顺序为自下而上、从右到左

ORACLE 采用自下而上从右到左的顺序解析Where 子句

SQL优化思路:根据这个原理,表之间的连接必须写在其他Where 条件之前, 可以过滤掉最大数量记录的条件必须写在Where 子句的末尾

3.group by--执行顺序从左往右分组

SQL优化思路:提高group by 语句的效率, 可以通过将不需要的记录在group by之前过滤掉。即在group by前使用where来过虑,而尽量避免group by后再having过滤

4.having 子句----很耗资源,尽量少用

SQL优化思路:避免使用having子句, having只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.

(非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,where 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的.

where 也应该比having 快点的,因为它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where 跟having比较了。

在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上后者要慢。
如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,where 的作用时间是在计算之前就完成的,而having 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

在多表联接查询时,on 比where 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where 进行过滤,然后再计算,计算完后再由having 进行过滤。

由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。

5.select子句--少用*号,尽量取字段名称。

ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 使用列名意味着将减少消耗时间。

sql 语句用大写的;因为 oracle 总是先解析 sql 语句,把小写的字母转换成大写的再执行

6.order by子句--执行顺序为从左到右排序,很耗资源



参考:

http://zoroeye.iteye.com/blog/2231332

https://blog.csdn.net/bitcarmanlee/article/details/51004767

https://www.cnblogs.com/Qian123/p/5669259.html

编辑:孙小北

本文地址: https://www.xiaowangyun.com/wyblog/detail/?id=253

版权归属: www.xiaowangyun.com   转载时请以链接形式注明出处

0 条评论

快来评论

物以类聚

最新评论

2017-10-06

一辈子不长,只有珍惜了,才不至于后悔。

2017-10-06

懂得感恩,才能走得更远。

标签云

归档

取消

感谢您的支持,您的每一次打赏都是一次鼓励!

扫码支持
每一次支持,都是不懈的动力

打开支付宝扫一扫,即可进行扫码打赏哦