一、绪论
作为关系型数据库管理系统(RDBMS,Relational DataBase Management System)的核心,SQL(Structured Query Language)能够方便地进行数据插入、查询、更新以及删除、创建修改数据库模式以及数据访问控制,使RDBMS逐步成为了当前网络时代下的新型基建。然而随着互联网的快速发展,流量呈现爆发式的增长,作为网络基建为了保证稳定可靠为互联网提供服务,在执行SQL时需要提供一定的优化手段,保证语句的高效执行,在降低数据库本身负载的同时,提供无感式服务。为了优化SQL语句,对SQL语句过程的熟悉了解就成为了优化的关键。接下来本文将从SQL执行流程的角度,介绍SQL执行流程中的每一个步骤,以及部分具体实践时的优势场景。
二、SQL执行流程
SQL语言中的关键字根据所负责的职能不同,可以分为SQL算子与谓词。算子是SQL语句执行过程中各个步骤的具体动作;谓词是一种只返回真值的特殊函数,下面将从算子与谓词两方面进行介绍。
2.1 算子
在SQL语句执行的过程中,有一个个执行单元负责实现SQL语句的目标结果,这些执行单元就是算子。各个算子之间的关系如同流水线上的工人,按照一定的顺序逐步访问数据。这里我们以SELECT语句为例,对SQL语句的执行顺序进行解释。现在有语句:
SELECT col_1, col_2, col_3, col_4, col_5 FROM Table_1 JOIN Table_2 USING col_1 WHERE col_1 < 10 GROUP BY col_3 HAVING SUM(col_4) >1000 ORDER BY col_5 LIMIT 10;
对于这句SQL而言,其中的SELECT 、SUM 、FROM、 WHERE、 GROUP BY、HAVING、ORDER BY、LIMIT都是SQL算子。其执行流程如下:
1.通过From节点选定要操作的数据对象,对于该语句即为From Table_1;
2.根据需要判断是否需要Filter介入Scan,否则直接Scan,对于该语句为WHERE col_1 < 10;
3.根据语句需要进行Join,对于该语句为JOIN Table_2 USING col_1;
4.根据语句需要进行Group以及Having与Order,对于该语句Group为GROUP BY col_3部分;Having为HAVING SUM(col_4);Order为ORDER BY col_5;
5.根据数据与源表内容进行Projection,对于该语句为SUM(col_4),以及col_1, col_2, col_3, col_4, col_5;
6.执行TopN单元,对该语句即为LIMIT 10;
针对该流程,下面对各个算子进行介绍。
From 算子 是SQL语句中最基本的算子,用于定位SQL语句的操作对象,主要出现在SELECT语句中,但DDL语句和DML语句中则隐式地包含了From算子。
Scan算子 是用于扫描操作的算子,作用于表和视图。Scan算子包含SeqScan算子和IndexScan算子等,提及的这两个分别是执行顺序扫描和基于索引扫描。
Filter算子 是条件过滤算子,用于在SQL语句中根据一定的条件过程表或视图中的数据。Filter算子中至少包含一个过滤条件,且Filter算子中可以包含非常复杂的过滤条件。
Join算子 是用于完成连接操作的所有算子的统称,Join算子本身包含了连接条件。在具体的SQL语句中,Join算子可以隐式表达,也可以表达为join…on…形式。
分组算子 是完成分组操作的算子,最常用的是Group算子和Having算子,还包括Cube算子、Rollup算子等。 Group算子是完成分组操作的核心算子,而having算子则提供了分组筛选条件。
Order算子 是SQL语句中用于执行排序操作的算子。排序操作是SQL语句中的常见操作,也是重要操作,而排序算子的具体实现,在不同的数据库中经常不同,同一种数据中也会提供多种算法用于完成排序。
投影算子 是SELECT语句中的必要组成部分,表达了SELECT语句的输出内容的结构。投影算子可以有多种形式,甚至投影列本身就是一个独立的SQL语句(子查询),最常见的表现形式是表或视图中的列,此外还可以表现为Scalar算子、Aggregation算子或Window算子。
- Scalar算子是完成标量运算的算子,都涉及到标量函数运算。
- Aggregation 算子是聚合运算算子,包括COUNT、MAX/MIN、SUM/AVG等,通常结合分组算子出现。
- Window算子是窗口操作算子,以窗口函数形式出现。Window算子是个复合结构,可以进一步细分为窗口函数算子、Over算子、Partition算子和Order算子。
Value算子 是完成非投影部分的求值运算的算子,一般表现为标量函数,通常出现于其他多种算子的各种表达式中,比如出现在Filter算子或Join算子中完成过滤条件表达式或连接条件表达式的求值运算。
Top N算子 是完成限定操作的算子的统称,限定操作指的是基于结果集并在结果集上完成某种行为的操作,Top N算子的最典型的应用场景是分页。Top N算子具体可以表达为Top、Limit、Offset、RowNum等关键字。
Exchange算子 是SQL语句执行过程中在各个执行步骤之内或之间完成数据交换的算子,在并行场景或分布式场景中起作用。Exchange算子是由数据库引擎调度的算子,其动作不能由人工参与。
2.2 谓词
谓词目的是为了给SQL命题提供判断真假的手段,即对于诸如BETWEEN、LIKE、IN、IS NULL、=、<、>等关键词都可以称之为SQL中谓词,它是一种返回值只为真值(TRUE/FALSE/UNKNOWN)的特殊函数。
谓词用于WHERE子句和HAVING子句的搜索条件中,还用于FROM子句的连接条件及需要布尔值的其他构造体中。
与谓词类似的结构还有函数,函数同样提供了返回值,但两者的不同在于:函数返回值有可能是数字、字符串或者日期等; 谓词的返回值全部是真值(TRUE/FALSE/UNKNOWN)。因此谓词的形式更像是编程语言中的布尔表达式。下面是对谓词的介绍。
LIKE谓词 模糊匹配,当需要进行字符串的部分一致查询时需要使用该谓词。 其中提到的部分一致大体可以分为前方一致(string%)、中间一致(%string%)和后方一致(%string)三种类型。
BETWEEN谓词 范围查询 使用BETWEEN可以进行范围查询,该谓词与其他谓词或者函数的不同之处在于它使用了3个参数(where a between c and d)。
IS NULL 、IS NOT NULL谓词 判断是否为NULL。为了选取出某些值为NULL 列的数据不能使用=,而只能使用特定的谓词IS NULL。
IN、NOT IN谓词:Or的简便用法。为了选取出值为某些固定结果的内容,可以使用Or。但当结果较多时where子句会非常长,因此可以使用In字句将(where a=1 or a=2 or a=3; )替换为(where a in (1, 2, 3))。同时IN可以用作子查询,即有(where a in (select * from t2))
EXISTS谓词 用于“判断是否存在满足某种条件的记录”。如果存在这样的记录就返回真(TRUE),如果不存在就返回假(FALSE)。 EXISTS(存在)谓词的主语是“记录”。EXISTS只需要在右侧书写1个参数,该参数通常都会是一个子查询。可以使用in(或者not in)代替。
- 这里需要注意的是,与IN不同的是,EXIST会将A表数据全部取出,然后循环A表与B表的每条数据并进行匹配,如果想等,则会将A表数据插入集合;而IN则是将AB两表同时取出查询子查询的表,然后做笛卡尔积并按条件筛选,适用于B表相对较小的场景。
三、总结
SQL执行部分的介绍就到这里,讲的相对较为浅显。更为具体实际上算子也可以再进行分类,根据职能,算子可以分为:扫描、连接、物化与控制节点。




