顺序说明
首先知道:在SQL中,子语句执行的顺序并不取决于它在整个SQL语句中所占据的位置的。执行的顺序是基于SQL规定的顺序来执行的。
接下来我们来具体解释下SQL规定的顺序是怎样的。
对于每个子句,都可以被划分到不同的执行模块中。这些执行模块分别为:得到基表,对基表进行分组,对分组表进行过滤,读取最终分组表的列。
上述所说的这些模块,它们在整个SQL语句中的执行顺序,且其与子句的对应关系,分别为:
- 得到基表 -> [from、join、where]
- 对基表进行分组 -> [group by]
- 对分组表进行过滤 -> [having]
- 读取最终分组表的列 -> [select]
在基于这4个执行模块中延伸出了一些子模块,它们是用来增强这些父模块的执行的:
- [聚合函数,ON] -> [having],
- [聚合函数,distinct,order by,limit] -> [select]
现在具体说明下这些子模块的执行顺序。
对于子模块[聚合函数,ON],聚合函数发生在ON之前。因为列需要先被计算处理,ON语句就能够基于已经被计算过了的列执行判断操作。当ON执行完了之后,才会触发HAVING,执行对行过滤的操作。
而对于子模块[聚合函数,distinct,order by,limit],其中聚合函数发生在select之前。当列被计算完成,select就能够直接读取已经被计算过了的列了,然后在此基础上,接着执行发生在select之后的[distinct,order by,limit]。[distinct,order by,limit]的执行顺序分别为,distinct -> order by -> limit。
这些模块的执行顺序如下图所示:
现在总结一下语句的执行顺序:
示例
举个例子说明下,假设有一种表名为order,结构如下:
需求是得到每个订单中总购买金额最高的商品。则SQL语句为:
select
order.order_id,
order.product_name,
sum(price * product_count) AS total_amount
from order
group by order.order_id
having on max(price * product_count) = sum(price * product_count)
这个SQL语句执行的顺序,则就是:
from -> group by -> [max,sum] -> on -> having -> sum -> select
每一个子语句的执行结果,也就是虚拟表,都会作为下一个子语句的操作表。就像是一个流一样,每个对象处理所生成的结果都会交由给下一个对象接着做处理,直到结束。
总结
- 在SQL中,子语句执行的顺序并不取决于它在整个SQL语句中所占据的位置。执行的顺序是基于SQL中规定的顺序来执行的。
- 每个阶段的SQL语句所生成的结果,在SQL的底层都会被存放进虚拟表中。这张表存放的都是来自上游语句所生成的结果,它对于我们来说是不可见的,只有当整个SQL语句都执行完毕后,最后的这个结果对我们才是可见的。
- SQL语句的执行,就像是一个流一样,每个子语句生成的结果都会流向下一个子语句中被处理,所以子语句都是基于上游SQL语句所生成结果进行操作的。