目录
一、样例
二、SELECT语句的处理过程
1. FROM阶段
2. WHERE阶段
3. GROUP BY阶段
4. HAVING阶段
5. SELECT阶段
6. ORDER BY阶段
三、样例解释
数据库SQL(Structure Query Language)包含3种类型的语言:DML(Data Manipulation Language)、DDL(Data Definition Language)和DCL(Data Control Language),其中使用最频繁的当属DML,DML包括4条具体的命令,它们是SELECT、UPDATE、INSERT、DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言。这4条命令中,使用最频繁的是SELECT命令,所有查询的操作都是通过它来获取数据库中的数据。但你是否有思考过,数据库执行SELECT命令的顺序是否与我们写出的SELECT命令的顺序一致?接下来,我们就来分析一下Oracle数据库执行SELECT命令的顺序。
先通过一个例子来看JOIN ON和WHERE执行结果的不同。
一、样例
CREATE TABLE"SCOTT"."A" (
"PERSON_ID"NUMBER(5) NULL,
"PERSON_NAME"VARCHAR2(255 BYTE) NULL)
;------------------------------
--Records of A
------------------------------
INSERT INTO "SCOTT"."A" VALUES ('1', '张三');INSERT INTO "SCOTT"."A" VALUES ('2', '李四');INSERT INTO "SCOTT"."A" VALUES ('3', '王五');INSERT INTO "SCOTT"."A" VALUES ('4', '赵六');INSERT INTO "SCOTT"."A" VALUES ('5', '周七');CREATE TABLE"SCOTT"."B" (
"PERSON_ID"NUMBER(5) NULL,
"LOVE_FRUIT"VARCHAR2(255 BYTE) NULL);------------------------------
--Records of B
------------------------------
INSERT INTO "SCOTT"."B" VALUES ('1', '香蕉');INSERT INTO "SCOTT"."B" VALUES ('2', '苹果');INSERT INTO "SCOTT"."B" VALUES ('3', '橘子');INSERT INTO "SCOTT"."B" VALUES ('4', '梨');INSERT INTO "SCOTT"."B" VALUES ('8', '桃');
查询语句1
SELECT * FROM A LEFT JOIN ORACLE.B ON A.PERSON_ID =B.PERSON_ID AND A.PERSON_ID =1;
查询语句2
SELECT * FROM A LEFT JOIN ORACLE.B ON A.PERSON_ID =B.PERSON_ID WHERE A.PERSON_ID =1;
为什么结果不同呢?可以从查询逻辑处理的过程解释。
二、SELECT语句的处理过程
我们知道,SQL 查询的大致语法结构如下:
(5)SELECT DISTINCT TOP() (1)FROM JOIN ON (2)WHERE (3)GROUP BY (4)HAVING (6)ORDER BY
SELECT语法的处理顺序:
The following steps show the processing order for a SELECT statement.
FROM
ON
JOIN
WHERE
GROUP BY
WITH CUBE or WITH ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
这些步骤执行时,每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入。这些虚拟表对调用者(客户端应用程序或者外部查询)不可用。只是最后一步生成的表才会返回给调用者。如果没有在查询中指定某一子句,将跳过相应的步骤。
SELECT各个阶段分别干了什么:
1. FROM阶段
FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种JOIN),主要有以下几个步骤:
求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(CROSS JOIN),求笛卡儿积,生成虚拟表VT1-J1。
ON筛选器。 这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。
添加外部行。如果指定了OUTER JOIN,还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。
经过以上步骤,FROM阶段就完成了。概括地讲,FROM阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了JOIN,还有APPLY,PIVOT,UNPIVOT)。
2. WHERE阶段
WHERE阶段是根据中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。
3. GROUP BY阶段
GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。
4. HAVING阶段
该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。
5. SELECT阶段
这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行:
计算SELECT列表中的表达式,生成VT5-1。
若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2。
若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2中选择签名指定数量或者百分比的行,生成VT5-3。
6. ORDER BY阶段
根据ORDER BY子句中指定的列明列表,对VT5-3中的行,进行排序,生成游标VC6。
三、样例解释
查询语句1的执行过程
SELECT * FROM A LEFT JOIN ORACLE.B ON A.PERSON_ID = B.PERSON_ID AND A.PERSON_ID = 1;
求笛卡尔积,产生5*5=25条记录
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
1
张三
2
苹果
1
张三
3
橘子
1
张三
4
梨
1
张三
8
桃
2
李四
1
香蕉
2
李四
2
苹果
2
李四
3
橘子
2
李四
4
梨
2
李四
8
桃
3
王五
1
香蕉
3
王五
2
苹果
3
王五
3
橘子
3
王五
4
梨
3
王五
8
桃
4
赵六
1
香蕉
4
赵六
2
苹果
4
赵六
3
橘子
4
赵六
4
梨
4
赵六
8
桃
5
周七
1
香蕉
5
周七
2
苹果
5
周七
3
橘子
5
周七
4
梨
5
周七
8
桃
ON筛选器(A.PERSON_ID=B.PERSON_ID AND A.PERSON_ID=1)
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
添加外部行
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
1
张三
1
张三
1
张三
1
张三
查询语句2的执行过程
SELECT * FROM A LEFT JOIN ORACLE.B ON A.PERSON_ID = B.PERSON_ID WHERE A.PERSON_ID = 1;
求笛卡尔积,产生5*5=25条记录
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
1
张三
2
苹果
1
张三
3
橘子
1
张三
4
梨
1
张三
8
桃
2
李四
1
香蕉
2
李四
2
苹果
2
李四
3
橘子
2
李四
4
梨
2
李四
8
桃
3
王五
1
香蕉
3
王五
2
苹果
3
王五
3
橘子
3
王五
4
梨
3
王五
8
桃
4
赵六
1
香蕉
4
赵六
2
苹果
4
赵六
3
橘子
4
赵六
4
梨
4
赵六
8
桃
5
周七
1
香蕉
5
周七
2
苹果
5
周七
3
橘子
5
周七
4
梨
5
周七
8
桃
ON筛选器 (A.PERSON_ID=B.PERSON_ID)
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
2
李四
2
苹果
3
王五
3
橘子
4
赵六
4
梨
添加外部行
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
2
李四
2
苹果
3
王五
3
橘子
4
赵六
4
梨
5
周七
WHERE阶段 (A.PERSON_ID=1)
A.PERSON_ID
PERSON_NAME
B.PERSON_ID
LOVE_FRUIT
1
张三
1
香蕉
有了上面的验证,我们可以猜测下面语句的执行结果
SELECT * FROM A LEFT JOIN ORACLE.B ON A.PERSON_ID =B.PERSON_ID;