SQL语句逻辑执行过程和相关语法详解

1.1 SQL语句的逻辑处理顺序

SQL语句的逻辑处理顺序,指的是SQL语句按照一定的规则,一整条语句应该如何执行,每一个关键字、子句部分在什么时刻执行。

除了逻辑顺序,还有物理执行顺序。物理顺序是SQL语句真正被执行时的顺序(执行计划),它是由各数据库系统的关系引擎中的语句分析器、优化器等等组件经过大量计算、分析决定的。

很多时候因为优化的关系,使得语句最终的物理执行顺序和逻辑顺序不同。按照逻辑顺序,有些应该先执行的过程,可能优化器会指定它后执行。但不管是逻辑顺序还是物理顺序,设计了一条SQL语句,语句最后返回的结果不会也不能因为物理顺序改变了逻辑顺序而改变。

其实,逻辑顺序只是为我们编写、理解SQL语句提供些帮助,除此之外,它毫无用处。而且,是不是真的存在一条严格且完整的执行顺序规则都是不确定的事情。虽然某些书上、网上给出了一些顺序(我个人所知道的比较权威的,是SQL Server的"圣书"技术内幕里介绍过),但在任何一种数据库系统的官方手册上都没有关于这方面的介绍文档。

SQL Server和Oracle在语句的逻辑处理顺序上是一致的,在这方面,它们严格遵守了标准SQL的要求,任何一个步骤都遵循了关系型数据库的范式要求。因为遵循了一些范式要求,导致标准SQL不允许使用某些语法。但是MySQL、MariaDB和它们小有不同,它们对标准SQL进行扩展,标准SQL中不允许使用的语法,在MySQL、MariaDB中可能可以使用,但很多时候这会违反关系模型的范式要求。

虽然本文的最初目的是介绍MariaDB/MySQL语句的逻辑处理顺序,但在篇幅上对标准SQL介绍的更多,因为它们符合规范。理解这些规范,实际上是在理解关系模型和集合模型。本文也在多处通过这两个模型来分析为什么标准SQL不允许某些语法,以及为什么MySQL可以支持这些"不标准"的语法

1.2 各数据库系统的语句逻辑处理顺序

以SELECT语句为例。

1.2.1 SQL Server和Oracle的逻辑执行顺序

如下图:

SQL语句逻辑执行过程和相关语法详解

关于本图需要说明的是,虽然图中给出的顺序是DISTINCT比ORDER BY先执行,这也是网上流传的版本。但其实,在DISTINCT和ORDER BY之间的顺序没有严格的界限,甚至ORDER BY的顺序要优先于DISTINCT后文会分析为什么。而且刚刚去翻了下sql server技术内幕中关于逻辑处理顺序的内容,发现它没有对DISTINCT执行位置进行排序,只是在介绍ORDER BY时提了下DISTINCT,我想也是因为DISTINCT和ORDER BY之间没有严格的顺序。

后面关于MySQL和mariadb的两张逻辑顺序图中,将会把DISTINCT和ORDER BY的顺序调换过来。

以下是对上述逻辑执行顺序的描述:

(1).首先从FROM语句中获取要操作的表并计算笛卡尔积。如果有要联接的表,则还获取联接表。对它们计算笛卡尔积,笛卡尔积的结果形成一张虚拟表vt1。

这里就体现了物理顺序和逻辑顺序的一个不同点:按照逻辑顺序,在执行SQL语句之初总是会进行笛卡尔积的计算,如果是两张或多张非常大的表,计算笛卡尔积是非常低效的行为,这是不能容忍的。所以物理顺序会进行一些优化决定,比如使用索引跳过一部分或整个笛卡尔积让计算变得很小。

(2).对虚拟表vt1执行ON筛选语句,得到虚拟表vt2。

(3).根据联接类型,将保留表的外部行添加到vt2中得到虚拟表vt3。

(4).对vt3执行where条件筛选,得到虚拟表vt4。

(5).执行分组,得到虚拟表vt5。

注意,分组之后,整个SQL的操作上下文就变成了分组列,而不再是表中的每一列,后续的一切操作都是围绕所分的组作为操作对象进行操作的。也就是说,不在分组列表中的列不能在后续步骤中使用。例如,使用"group by a"对a列分组,那么后续的select列表中就不能使用b列,除非是对b列进行分组聚合运算。SQL Server、Oracle和MariaDB、Mysql最大的区别就在于此步,后两者可以引用分组列以外的列。

(6).对vt5执行集合操作cube或者rollup,得到虚拟表vt6。

(7).对分组的最终结果vt6执行having筛选,得到虚拟表vt7。

(8).根据给定的选择列列表,将vt7中的选择列插入到虚拟表vt8中。

注意,选择列是"同时性操作",在选择列中不能使用列别名来引用列表中的其他列。例如select col1+1 as a,a+1 as b from t1是错误的,因为"col1+1"和"a+1"之间没有执行上的先后顺序,所以它认为"a+1"中的a列是不存在的。

(9).对vt8进行窗口分组相关的计算,得到虚拟表vt9。

(10).对vt9按照指定的列去除重复行,得到虚拟表vt10。

这一步是将数据复制到内存中相同的临时表结构中进行的,不过该临时表多出了一个唯一性索引列用来做重复消除。

(11).对vt10进行排序,排序后的表为虚拟表vt11。

(12).从vt11中根据top条件挑出其中满足的行,得到虚拟表vt12。

如果没有应用order by,则记录是无序的集合,top挑出的行可能是随机的。也因此top一般要和order by字句一起使用。

(13).将vt12从服务端返回给客户端作为最终查询结果。

1.2.2 MariaDB的逻辑执行顺序

如下图:

SQL语句逻辑执行过程和相关语法详解

MariaDB中,使用的是LIMIT子句实现和TOP子句一样的功能:限制输出行数。且它不支持"WITH CUBE"(直接忽略该关键词)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/90c3b57f9b6508b170ad70d479052a49.html