目錄
一、樣例
二、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(<top_specification>) <select_list> (1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate> (2)WHERE <where_predicate> (3)GROUP BY <group_by_specification> (4)HAVING <having_predicate> (6)ORDER BY <order_by_list>
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階段是根據<where_predicate>中條件對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;