上一篇講述了Oracle的SELECT語法的執行順序,這篇講述MySQL的SELECT語法的執行順序。MySQL的SELECT語法的執行順序和Oracle的基本相同,只是增加了MySQL獨有的LIMIT語法。
目錄
一、SELECT語句的處理過程
1. FROM階段
2. WHERE階段
3. GROUP BY階段
4. HAVING階段
5. SELECT階段
6. ORDER BY階段
7. LIMIT階段
一、SELECT語句的處理過程
查詢操作是關系數據庫中使用最為頻繁的操作,也是構成其他SQL語句(如DELETE、UPDATE)的基礎。
我們知道,SQL 查詢的大致語法結構如下:
(5)SELECT DISTINCT <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>
(7)LIMIT n, m
查詢處理的順序如下:
- FROM
- ON
- JOIN
- WHERE
- GROUP BY
- HAVING
- SELECT
- DISTINCT
- ORDER BY
- LIMIT
這些步驟執行時,每個步驟都會產生一個虛擬表,該虛擬表被用作下一個步驟的輸入。這些虛擬表對調用者(客戶端應用程序或者外部查詢)不可用。只是最后一步生成的表才會返回給調用者。如果沒有在查詢中指定某一子句,將跳過相應的步驟。
SELECT各個階段分別干了什么:
1. FROM階段
FROM階段標識出查詢的來源表,並處理表運算符。在涉及到聯接運算的查詢中(各種JOIN),主要有以下幾個步驟:
- 求笛卡爾積。不論是什么類型的聯接運算,首先都是執行交叉連接(CROSS JOIN),求笛卡兒積(Cartesian product),生成虛擬表VT1-J1。
- ON篩選器。 這個階段對上個步驟生成的VT1-J1進行篩選,根據ON子句中出現的謂詞進行篩選,讓謂詞取值為true的行通過了考驗,插入到VT1-J2。
- 添加外部行。如果指定了OUTER JOIN,如LEFT OUTERJOIN、RIGHT OUTER JOIN),還需要將VT1-J2中沒有找到匹配的行,作為外部行添加到VT1-J2中,生成VT1-J3。如果FROM子句包含兩個以上表,則對上一個連接生成的結果表VT1-J3和下一個表重復依次執行3個步驟,直到處理完所有的表為止。
經過以上步驟,FROM階段就完成了。
2. WHERE階段
WHERE階段是根據<where_predicate>中條件對VT1中的行進行篩選,讓條件成立的行才會插入到VT2中。此時數據還沒有分組,所以不能在WHERE中出現對統計的過濾。
3. GROUP BY階段
GROUP階段按照指定的列名列表,將VT2中的行進行分組,生成VT3。最后每個分組只有一行。在GROUP BY階段,數據庫認為兩個NULL值是相等的,因此會將NULL值分到同一個分組中。
4. HAVING階段
該階段根據HAVING子句中出現的謂詞對VT3的分組進行篩選,並將符合條件的組插入到VT4中。COUNT(expr) 會返回expr不為NULL的行數,count(1)、count(*)會返回包括NULL值在內的所有數量。
5. SELECT階段
這個階段是投影的過程,處理SELECT子句提到的元素,產生VT5。這個步驟一般按下列順序進行:
- 計算SELECT列表中的表達式,生成VT5-1。
- 若有DISTINCT,則刪除VT5-1中的重復行,生成VT5-2。
6. ORDER BY階段
根據ORDER BY子句中指定的列明列表,對VT5-2中的行,進行排序,生成VT6。如果不指定排序,數據並非總是按照主鍵順序進行排序的。NULL被視為最小值。
7. LIMIT階段
取出指定行的記錄,產生虛擬表VT7,並返回給查詢用戶。LIMIT n, m的效率是十分低的,一般可以通過在WHERE條件中指定范圍來優化 WHERE id > ? limit 10。