目录
1.FROM 子句连接
2.ON 子句过滤
3.JOIN 子句连接
4.WHERE 子句过滤
5.GROUP BY 子句(开始使用select中的别名,后面的语句中都可以使用)
6.cube或者rollup
7.HAVING 子句(很耗资源,尽量少用)
8.SELECT 子句
9.DISTINCT 子句
10.ORDER BY 子句
11.LIMIT 子句
有一次面试被问到:你知道SQL语句的执行顺序吗?
瞬间懵逼,平时写的sql语句倒是不少,但是并没有关心它是按什么顺序执行的。所以只能回家等通知了(我猜面试官肯定心里在想,连这个都不会,还出敢来面试。开个玩笑~)。
今天抽时间整理一下,加深自己的印象,同时希望能够帮助其他小伙伴,废话不多说,直接上一个连表查询的sql语句:
SELECT
DISTINCT
< select_list >
FROM
< left_table > < join_type >
JOIN < right_table >
ON < join_condition >
WHERE
< where_condition >
GROUP BY
< group_by_list >
HAVING
< having_condition >
ORDER BY
< order_by_condition >
LIMIT < limit_number >
执行顺序:FROM ... WHERE ... GROUP BY ... HAVING ... SELECT .... DISTINCT ... ORDER BY ... LIMIT
对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1。
首先先来解释一下什么是笛卡尔积
现在我们有两个集合 A = {0,1} , B = {2,3,4}
那么,集合 A * B 得到的结果就是
A * B = {(0,2)、(1,2)、(0,3)、(1,3)、(0,4)、(1,4)};
B * A = {(2,0)、{2,1}、{3,0}、{3,1}、{4,0}、(4,1)};
上面 A * B 和 B * A 的结果就可以称为两个集合相乘的 笛卡尔积
我们可以得出结论,A 集合和 B 集合相乘,包含了集合 A 中的元素和集合 B 中元素之和,也就是 A 元素的个数 * B 元素的个数。
那什么是虚表呢?
在 MySQL 中,有三种类型的表
一种是永久表,永久表就是创建以后用来长期保存数据的表
一种是临时表,临时表也有两类,一种是和永久表一样,只保存临时数据,但是能够长久存在的;还有一种是临时创建的,SQL 语句执行完成就会删除。
一种是虚表,虚表其实就是视图,数据可能会来自多张表的执行结果。
然后对 FROM 连接的结果进行 ON 筛选,将 ON 中的逻辑表达式将应用到 VT1 中的各个行,筛选出满足ON逻辑表达式的行,生成虚拟表 VT2,把符合记录的条件存在 VT2 中。
如果是outer join(left join、rigth join),那么这一步就将添加外部行,left outer jion 就把左表在第二步中过滤的添加进来,right outer join 那么就将右表在第二步中过滤掉的行添加进来,这样生成虚拟表 VT3。
如果 from 子句中的表数目大于两个表,那么就将VT3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表VT3。
对虚拟表VT3进行WHERE条件过滤。只有符合
WHERE 和 ON 的区别
- 如果有外部列,ON 针对过滤的是关联表,主表(保留表)会返回所有的列;
- 如果没有添加外部列,两者的效果是一样的;
应用
- 对主表的过滤应该使用 WHERE;
- 对于关联表,先条件查询后连接则用 ON,先连接后条件查询则用 WHERE;
group by 子句将中的唯一的值组合成为一组,产生虚拟机表 VT5。如果应用了group by,那么后面的所有步骤都只能得到的 VT5 的列或者是聚合函数(count、sum、avg等)。原因在于最终的结果集中只为每个组包含一行。
应用cube或者rollup选项,为VT5生成超组,生成VT6。
应用having筛选器,把符合条件的放在VT7。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。
避免使用HAVING 子句,HAVING 只会在检索出所有记录之后才对结果集进行过滤。这个处理需要排序、总计等操作。
如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销。
执行select操作,在VT7中筛选出select指定的列,插入到虚拟表VT8中。
少用*号,尽量取字段名称。
应用distinct子句,在VT8中移除相同的行,生成 VT9。
事实上如果应用了group by子句那么distinct是多余的,原因在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,那么所有的记录都将是不相同的。
应用 order by 子句。按照 order_by_condition 排序 VT9,此时返回的一个游标,而不是虚拟表。sql 是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。
对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使用order by 子句查询不能应用于表表达式。排序是很需要成本的,除非你必须要排序,否则最好不要指定order by。在这一步中是第一个也是唯一一个可以使用select列表中别名的步骤。
limit 子句从上一步得到的结果中选出从指定位置开始的指定行数据,常用来做分页。
参考:
https://blog.csdn.net/qq_36894974/article/details/105594307
https://www.cnblogs.com/yyjie/p/7788428.html