'SQL查詢語句的執行順序解析'

SQL 軟件測試開發技術棧 2019-09-07
"

SQL語句執行順序

"

SQL語句執行順序

SQL查詢語句的執行順序解析

結合上圖,整理出如下偽SQL查詢語句。

"

SQL語句執行順序

SQL查詢語句的執行順序解析

結合上圖,整理出如下偽SQL查詢語句。

SQL查詢語句的執行順序解析

從這個順序中我們可以發現,所有的查詢語句都是從 FROM 開始執行的。在實際執行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入。 接下來,我們詳細的介紹下每個步驟的具體執行過程。


1 FROM 執行笛卡爾積

FROM 才是 SQL 語句執行的第一步,並非 SELECT 。對FROM子句中的前兩個表執行笛卡爾積(交叉聯接),生成虛擬表VT1,獲取不同數據源的數據集。

FROM子句執行順序為從後往前、從右到左,FROM 子句中寫在最後的表(基礎表 driving table)將被最先處理,即最後的表為驅動表,當FROM 子句中包含多個表的情況下,我們需要選擇數據最少的表作為基礎表。


2 ON 應用ON過濾器

對虛擬表VT1 應用ON篩選器,ON 中的邏輯表達式將應用到虛擬表 VT1中的各個行,篩選出滿足ON 邏輯表達式的行,生成虛擬表 VT2


3 JOIN 添加外部行

如果指定了OUTER JOIN保留表中未找到匹配的行將作為外部行添加到虛擬表 VT2,生成虛擬表 VT3。保留表如下:

  • LEFT OUTER JOIN把左表記為保留表
  • RIGHT OUTER JOIN把右表記為保留表
  • FULL OUTER JOIN把左右表都作為保留表

在虛擬表 VT2表的基礎上添加保留表中被過濾條件過濾掉的數據,非保留表中的數據被賦予NULL值,最後生成虛擬表 VT3

如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1~3,直到處理完所有的表為止。


4 WHERE 應用WEHRE過濾器

對虛擬表 VT3應用WHERE篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表 VT4

  • 由於數據還沒有分組,因此現在還不能在WHERE過濾器中使用聚合函數對分組統計的過濾。
  • 同時,由於還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的。

5 GROUP BY 分組

按GROUP BY子句中的列/列表將虛擬表 VT4中的行唯一的值組合成為一組,生成虛擬表VT5。如果應用了GROUP BY,那麼後面的所有步驟都只能得到的虛擬表VT5的列或者是聚合函數(count、sum、avg等)。原因在於最終的結果集中只為每個組包含一行。

同時,從這一步開始,後面的語句中都可以使用SELECT中的別名。


6 AGG_FUNC 計算聚合函數

計算 max 等聚合函數。SQL Aggregate 函數計算從列中取得的值,返回一個單一的值。常用的 Aggregate 函數包涵以下幾種:

  • AVG:返回平均值
  • COUNT:返回行數
  • FIRST:返回第一個記錄的值
  • LAST:返回最後一個記錄的值
  • MAX: 返回最大值
  • MIN:返回最小值
  • SUM: 返回總和

7 WITH 應用ROLLUP或CUBE

對虛擬表 VT5應用ROLLUP或CUBE選項,生成虛擬表 VT6

CUBE 和 ROLLUP 區別如下:

  • CUBE 生成的結果數據集顯示了所選列中值的所有組合的聚合。
  • ROLLUP 生成的結果數據集顯示了所選列中值的某一層次結構的聚合。

8 HAVING 應用HAVING過濾器

對虛擬表VT6應用HAVING篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表VT7。

HAVING 語句在SQL中的主要作用與WHERE語句作用是相同的,但是HAVING是過濾聚合值,在 SQL 中增加 HAVING 子句原因就是,WHERE 關鍵字無法與聚合函數一起使用,HAVING子句主要和GROUP BY子句配合使用。


9 SELECT 選出指定列

將虛擬表 VT7中的在SELECT中出現的列篩選出來,並對字段進行處理,計算SELECT子句中的表達式,產生虛擬表 VT8


10 DISTINCT 行去重

將重複的行從虛擬表 VT8中移除,產生虛擬表 VT9。DISTINCT用來刪除重複行,只保留唯一的。


11 ORDER BY 排列

將虛擬表 VT9中的行按ORDER BY 子句中的列/列表排序,生成遊標 VC10 ,注意不是虛擬表。因此使用 ORDER BY 子句查詢不能應用於表達式。同時,ORDER BY子句的執行順序為從左到右排序,是非常消耗資源的。


12 LIMIT/OFFSET 指定返回行

從VC10的開始處選擇指定數量行,生成虛擬表 VT11,並返回調用者。


實例

接下來,我們看一個實例,以下SQL查詢語句是否存在問題?

"

SQL語句執行順序

SQL查詢語句的執行順序解析

結合上圖,整理出如下偽SQL查詢語句。

SQL查詢語句的執行順序解析

從這個順序中我們可以發現,所有的查詢語句都是從 FROM 開始執行的。在實際執行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入。 接下來,我們詳細的介紹下每個步驟的具體執行過程。


1 FROM 執行笛卡爾積

FROM 才是 SQL 語句執行的第一步,並非 SELECT 。對FROM子句中的前兩個表執行笛卡爾積(交叉聯接),生成虛擬表VT1,獲取不同數據源的數據集。

FROM子句執行順序為從後往前、從右到左,FROM 子句中寫在最後的表(基礎表 driving table)將被最先處理,即最後的表為驅動表,當FROM 子句中包含多個表的情況下,我們需要選擇數據最少的表作為基礎表。


2 ON 應用ON過濾器

對虛擬表VT1 應用ON篩選器,ON 中的邏輯表達式將應用到虛擬表 VT1中的各個行,篩選出滿足ON 邏輯表達式的行,生成虛擬表 VT2


3 JOIN 添加外部行

如果指定了OUTER JOIN保留表中未找到匹配的行將作為外部行添加到虛擬表 VT2,生成虛擬表 VT3。保留表如下:

  • LEFT OUTER JOIN把左表記為保留表
  • RIGHT OUTER JOIN把右表記為保留表
  • FULL OUTER JOIN把左右表都作為保留表

在虛擬表 VT2表的基礎上添加保留表中被過濾條件過濾掉的數據,非保留表中的數據被賦予NULL值,最後生成虛擬表 VT3

如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1~3,直到處理完所有的表為止。


4 WHERE 應用WEHRE過濾器

對虛擬表 VT3應用WHERE篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表 VT4

  • 由於數據還沒有分組,因此現在還不能在WHERE過濾器中使用聚合函數對分組統計的過濾。
  • 同時,由於還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的。

5 GROUP BY 分組

按GROUP BY子句中的列/列表將虛擬表 VT4中的行唯一的值組合成為一組,生成虛擬表VT5。如果應用了GROUP BY,那麼後面的所有步驟都只能得到的虛擬表VT5的列或者是聚合函數(count、sum、avg等)。原因在於最終的結果集中只為每個組包含一行。

同時,從這一步開始,後面的語句中都可以使用SELECT中的別名。


6 AGG_FUNC 計算聚合函數

計算 max 等聚合函數。SQL Aggregate 函數計算從列中取得的值,返回一個單一的值。常用的 Aggregate 函數包涵以下幾種:

  • AVG:返回平均值
  • COUNT:返回行數
  • FIRST:返回第一個記錄的值
  • LAST:返回最後一個記錄的值
  • MAX: 返回最大值
  • MIN:返回最小值
  • SUM: 返回總和

7 WITH 應用ROLLUP或CUBE

對虛擬表 VT5應用ROLLUP或CUBE選項,生成虛擬表 VT6

CUBE 和 ROLLUP 區別如下:

  • CUBE 生成的結果數據集顯示了所選列中值的所有組合的聚合。
  • ROLLUP 生成的結果數據集顯示了所選列中值的某一層次結構的聚合。

8 HAVING 應用HAVING過濾器

對虛擬表VT6應用HAVING篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表VT7。

HAVING 語句在SQL中的主要作用與WHERE語句作用是相同的,但是HAVING是過濾聚合值,在 SQL 中增加 HAVING 子句原因就是,WHERE 關鍵字無法與聚合函數一起使用,HAVING子句主要和GROUP BY子句配合使用。


9 SELECT 選出指定列

將虛擬表 VT7中的在SELECT中出現的列篩選出來,並對字段進行處理,計算SELECT子句中的表達式,產生虛擬表 VT8


10 DISTINCT 行去重

將重複的行從虛擬表 VT8中移除,產生虛擬表 VT9。DISTINCT用來刪除重複行,只保留唯一的。


11 ORDER BY 排列

將虛擬表 VT9中的行按ORDER BY 子句中的列/列表排序,生成遊標 VC10 ,注意不是虛擬表。因此使用 ORDER BY 子句查詢不能應用於表達式。同時,ORDER BY子句的執行順序為從左到右排序,是非常消耗資源的。


12 LIMIT/OFFSET 指定返回行

從VC10的開始處選擇指定數量行,生成虛擬表 VT11,並返回調用者。


實例

接下來,我們看一個實例,以下SQL查詢語句是否存在問題?

SQL查詢語句的執行順序解析

首先,我們先看下如上SQL的執行順序,如下:

  1. 首先執行 FROM 子句, 從學生成績表中組裝數據源的數據。
  2. 執行 WHERE 子句, 篩選學生成績表中所有學生的數學成績不為 NULL 的數據 。
  3. 執行 GROUP BY 子句, 把學生成績表按 "班級" 字段進行分組。
  4. 計算 avg 聚合函數, 按找每個班級分組求出 數學平均成績
  5. 執行 HAVING 子句, 篩選出班級 數學平均成績大於 75 分的。
  6. 執行SELECT語句,返回數據,但彆著急,還需要執行後面幾個步驟。
  7. 執行 ORDER BY 子句, 把最後的結果按 "數學平均成績" 進行排序。
  8. 執行LIMIT ,限制僅返回3條數據。結合ORDER BY 子句,即返回所有班級中數學平均成績的前三的班級及其數學平均成績。

思考一下,如果我們將上面語句改成,如下會怎樣?

"

SQL語句執行順序

SQL查詢語句的執行順序解析

結合上圖,整理出如下偽SQL查詢語句。

SQL查詢語句的執行順序解析

從這個順序中我們可以發現,所有的查詢語句都是從 FROM 開始執行的。在實際執行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入。 接下來,我們詳細的介紹下每個步驟的具體執行過程。


1 FROM 執行笛卡爾積

FROM 才是 SQL 語句執行的第一步,並非 SELECT 。對FROM子句中的前兩個表執行笛卡爾積(交叉聯接),生成虛擬表VT1,獲取不同數據源的數據集。

FROM子句執行順序為從後往前、從右到左,FROM 子句中寫在最後的表(基礎表 driving table)將被最先處理,即最後的表為驅動表,當FROM 子句中包含多個表的情況下,我們需要選擇數據最少的表作為基礎表。


2 ON 應用ON過濾器

對虛擬表VT1 應用ON篩選器,ON 中的邏輯表達式將應用到虛擬表 VT1中的各個行,篩選出滿足ON 邏輯表達式的行,生成虛擬表 VT2


3 JOIN 添加外部行

如果指定了OUTER JOIN保留表中未找到匹配的行將作為外部行添加到虛擬表 VT2,生成虛擬表 VT3。保留表如下:

  • LEFT OUTER JOIN把左表記為保留表
  • RIGHT OUTER JOIN把右表記為保留表
  • FULL OUTER JOIN把左右表都作為保留表

在虛擬表 VT2表的基礎上添加保留表中被過濾條件過濾掉的數據,非保留表中的數據被賦予NULL值,最後生成虛擬表 VT3

如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1~3,直到處理完所有的表為止。


4 WHERE 應用WEHRE過濾器

對虛擬表 VT3應用WHERE篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表 VT4

  • 由於數據還沒有分組,因此現在還不能在WHERE過濾器中使用聚合函數對分組統計的過濾。
  • 同時,由於還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的。

5 GROUP BY 分組

按GROUP BY子句中的列/列表將虛擬表 VT4中的行唯一的值組合成為一組,生成虛擬表VT5。如果應用了GROUP BY,那麼後面的所有步驟都只能得到的虛擬表VT5的列或者是聚合函數(count、sum、avg等)。原因在於最終的結果集中只為每個組包含一行。

同時,從這一步開始,後面的語句中都可以使用SELECT中的別名。


6 AGG_FUNC 計算聚合函數

計算 max 等聚合函數。SQL Aggregate 函數計算從列中取得的值,返回一個單一的值。常用的 Aggregate 函數包涵以下幾種:

  • AVG:返回平均值
  • COUNT:返回行數
  • FIRST:返回第一個記錄的值
  • LAST:返回最後一個記錄的值
  • MAX: 返回最大值
  • MIN:返回最小值
  • SUM: 返回總和

7 WITH 應用ROLLUP或CUBE

對虛擬表 VT5應用ROLLUP或CUBE選項,生成虛擬表 VT6

CUBE 和 ROLLUP 區別如下:

  • CUBE 生成的結果數據集顯示了所選列中值的所有組合的聚合。
  • ROLLUP 生成的結果數據集顯示了所選列中值的某一層次結構的聚合。

8 HAVING 應用HAVING過濾器

對虛擬表VT6應用HAVING篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表VT7。

HAVING 語句在SQL中的主要作用與WHERE語句作用是相同的,但是HAVING是過濾聚合值,在 SQL 中增加 HAVING 子句原因就是,WHERE 關鍵字無法與聚合函數一起使用,HAVING子句主要和GROUP BY子句配合使用。


9 SELECT 選出指定列

將虛擬表 VT7中的在SELECT中出現的列篩選出來,並對字段進行處理,計算SELECT子句中的表達式,產生虛擬表 VT8


10 DISTINCT 行去重

將重複的行從虛擬表 VT8中移除,產生虛擬表 VT9。DISTINCT用來刪除重複行,只保留唯一的。


11 ORDER BY 排列

將虛擬表 VT9中的行按ORDER BY 子句中的列/列表排序,生成遊標 VC10 ,注意不是虛擬表。因此使用 ORDER BY 子句查詢不能應用於表達式。同時,ORDER BY子句的執行順序為從左到右排序,是非常消耗資源的。


12 LIMIT/OFFSET 指定返回行

從VC10的開始處選擇指定數量行,生成虛擬表 VT11,並返回調用者。


實例

接下來,我們看一個實例,以下SQL查詢語句是否存在問題?

SQL查詢語句的執行順序解析

首先,我們先看下如上SQL的執行順序,如下:

  1. 首先執行 FROM 子句, 從學生成績表中組裝數據源的數據。
  2. 執行 WHERE 子句, 篩選學生成績表中所有學生的數學成績不為 NULL 的數據 。
  3. 執行 GROUP BY 子句, 把學生成績表按 "班級" 字段進行分組。
  4. 計算 avg 聚合函數, 按找每個班級分組求出 數學平均成績
  5. 執行 HAVING 子句, 篩選出班級 數學平均成績大於 75 分的。
  6. 執行SELECT語句,返回數據,但彆著急,還需要執行後面幾個步驟。
  7. 執行 ORDER BY 子句, 把最後的結果按 "數學平均成績" 進行排序。
  8. 執行LIMIT ,限制僅返回3條數據。結合ORDER BY 子句,即返回所有班級中數學平均成績的前三的班級及其數學平均成績。

思考一下,如果我們將上面語句改成,如下會怎樣?

SQL查詢語句的執行順序解析

我們發現,若將 avg(數學成績) > 75 放到WHERE子句中,此時GROUP BY語句還未執行,因此此時聚合值 avg(數學成績) 還是未知的,因此會報錯。

"

SQL語句執行順序

SQL查詢語句的執行順序解析

結合上圖,整理出如下偽SQL查詢語句。

SQL查詢語句的執行順序解析

從這個順序中我們可以發現,所有的查詢語句都是從 FROM 開始執行的。在實際執行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入。 接下來,我們詳細的介紹下每個步驟的具體執行過程。


1 FROM 執行笛卡爾積

FROM 才是 SQL 語句執行的第一步,並非 SELECT 。對FROM子句中的前兩個表執行笛卡爾積(交叉聯接),生成虛擬表VT1,獲取不同數據源的數據集。

FROM子句執行順序為從後往前、從右到左,FROM 子句中寫在最後的表(基礎表 driving table)將被最先處理,即最後的表為驅動表,當FROM 子句中包含多個表的情況下,我們需要選擇數據最少的表作為基礎表。


2 ON 應用ON過濾器

對虛擬表VT1 應用ON篩選器,ON 中的邏輯表達式將應用到虛擬表 VT1中的各個行,篩選出滿足ON 邏輯表達式的行,生成虛擬表 VT2


3 JOIN 添加外部行

如果指定了OUTER JOIN保留表中未找到匹配的行將作為外部行添加到虛擬表 VT2,生成虛擬表 VT3。保留表如下:

  • LEFT OUTER JOIN把左表記為保留表
  • RIGHT OUTER JOIN把右表記為保留表
  • FULL OUTER JOIN把左右表都作為保留表

在虛擬表 VT2表的基礎上添加保留表中被過濾條件過濾掉的數據,非保留表中的數據被賦予NULL值,最後生成虛擬表 VT3

如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重複執行步驟1~3,直到處理完所有的表為止。


4 WHERE 應用WEHRE過濾器

對虛擬表 VT3應用WHERE篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表 VT4

  • 由於數據還沒有分組,因此現在還不能在WHERE過濾器中使用聚合函數對分組統計的過濾。
  • 同時,由於還沒有進行列的選取操作,因此在SELECT中使用列的別名也是不被允許的。

5 GROUP BY 分組

按GROUP BY子句中的列/列表將虛擬表 VT4中的行唯一的值組合成為一組,生成虛擬表VT5。如果應用了GROUP BY,那麼後面的所有步驟都只能得到的虛擬表VT5的列或者是聚合函數(count、sum、avg等)。原因在於最終的結果集中只為每個組包含一行。

同時,從這一步開始,後面的語句中都可以使用SELECT中的別名。


6 AGG_FUNC 計算聚合函數

計算 max 等聚合函數。SQL Aggregate 函數計算從列中取得的值,返回一個單一的值。常用的 Aggregate 函數包涵以下幾種:

  • AVG:返回平均值
  • COUNT:返回行數
  • FIRST:返回第一個記錄的值
  • LAST:返回最後一個記錄的值
  • MAX: 返回最大值
  • MIN:返回最小值
  • SUM: 返回總和

7 WITH 應用ROLLUP或CUBE

對虛擬表 VT5應用ROLLUP或CUBE選項,生成虛擬表 VT6

CUBE 和 ROLLUP 區別如下:

  • CUBE 生成的結果數據集顯示了所選列中值的所有組合的聚合。
  • ROLLUP 生成的結果數據集顯示了所選列中值的某一層次結構的聚合。

8 HAVING 應用HAVING過濾器

對虛擬表VT6應用HAVING篩選器。根據指定的條件對數據進行篩選,並把滿足的數據插入虛擬表VT7。

HAVING 語句在SQL中的主要作用與WHERE語句作用是相同的,但是HAVING是過濾聚合值,在 SQL 中增加 HAVING 子句原因就是,WHERE 關鍵字無法與聚合函數一起使用,HAVING子句主要和GROUP BY子句配合使用。


9 SELECT 選出指定列

將虛擬表 VT7中的在SELECT中出現的列篩選出來,並對字段進行處理,計算SELECT子句中的表達式,產生虛擬表 VT8


10 DISTINCT 行去重

將重複的行從虛擬表 VT8中移除,產生虛擬表 VT9。DISTINCT用來刪除重複行,只保留唯一的。


11 ORDER BY 排列

將虛擬表 VT9中的行按ORDER BY 子句中的列/列表排序,生成遊標 VC10 ,注意不是虛擬表。因此使用 ORDER BY 子句查詢不能應用於表達式。同時,ORDER BY子句的執行順序為從左到右排序,是非常消耗資源的。


12 LIMIT/OFFSET 指定返回行

從VC10的開始處選擇指定數量行,生成虛擬表 VT11,並返回調用者。


實例

接下來,我們看一個實例,以下SQL查詢語句是否存在問題?

SQL查詢語句的執行順序解析

首先,我們先看下如上SQL的執行順序,如下:

  1. 首先執行 FROM 子句, 從學生成績表中組裝數據源的數據。
  2. 執行 WHERE 子句, 篩選學生成績表中所有學生的數學成績不為 NULL 的數據 。
  3. 執行 GROUP BY 子句, 把學生成績表按 "班級" 字段進行分組。
  4. 計算 avg 聚合函數, 按找每個班級分組求出 數學平均成績
  5. 執行 HAVING 子句, 篩選出班級 數學平均成績大於 75 分的。
  6. 執行SELECT語句,返回數據,但彆著急,還需要執行後面幾個步驟。
  7. 執行 ORDER BY 子句, 把最後的結果按 "數學平均成績" 進行排序。
  8. 執行LIMIT ,限制僅返回3條數據。結合ORDER BY 子句,即返回所有班級中數學平均成績的前三的班級及其數學平均成績。

思考一下,如果我們將上面語句改成,如下會怎樣?

SQL查詢語句的執行順序解析

我們發現,若將 avg(數學成績) > 75 放到WHERE子句中,此時GROUP BY語句還未執行,因此此時聚合值 avg(數學成績) 還是未知的,因此會報錯。

SQL查詢語句的執行順序解析


"

相關推薦

推薦中...