概述
一條普通的SQL查詢(xún)語(yǔ)句它在MySQL數(shù)據(jù)庫(kù)中是怎么樣被解析和執(zhí)行的呢?下面一起來(lái)了解一下,MySQL是如何解析SQL查詢(xún)語(yǔ)句的,這對(duì)理解MySQL的執(zhí)行計(jì)劃也大有益處。
解析順序
下面是一條普通的SQL查詢(xún)語(yǔ)句偽代碼
SELECT DISTINCT
< select_list >
FROM
< left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
< where_condition >
GROUP BY
< group_by_list >
HAVING
< having_condition >
ORDER BY
< order_by_condition >
LIMIT < limit_number >
它的解析順序,實(shí)際上是下面這樣子的
1 FROM <left_table>
2 ON <join_condition>
3 <join_type> JOIN <right_table> 第2步和第3步會(huì)循環(huán)執(zhí)行
4 WHERE <where_condition> 第4步會(huì)循環(huán)執(zhí)行,多個(gè)條件的執(zhí)行順序是從左往右的。
5 GROUP BY <group_by_list>
6 HAVING <having_condition>
7 SELECT 分組之后才會(huì)執(zhí)行SELECT
8 DISTINCT <select_list>
9 ORDER BY <order_by_condition>
10 LIMIT <limit_number> 前9步都是SQL92標(biāo)準(zhǔn)語(yǔ)法。limit是MySQL的獨(dú)有語(yǔ)法。
MySQL是關(guān)系型數(shù)據(jù)庫(kù),基于行和列的結(jié)構(gòu)。SQL語(yǔ)句查詢(xún),目的就是檢索數(shù)據(jù)庫(kù)中符合條件的數(shù)據(jù)行和列,反過(guò)來(lái)說(shuō)就是把結(jié)果集中不符合條件的數(shù)據(jù)行和列過(guò)濾掉,然后返回符合條件的數(shù)據(jù)行和列。從整個(gè)角度出發(fā),可以把一條SQL語(yǔ)句及其解析順序的構(gòu)成歸納以下4個(gè)部分
- 行過(guò)濾
步驟1~6對(duì)數(shù)據(jù)行進(jìn)行過(guò)濾
- 列過(guò)濾
步驟7~8對(duì)數(shù)據(jù)列進(jìn)行過(guò)濾
- 排序
步驟9對(duì)數(shù)據(jù)結(jié)果進(jìn)行排序
- 分頁(yè)
步驟10是MySQL特有的屬性,它對(duì)數(shù)據(jù)結(jié)果進(jìn)行分頁(yè)
解析細(xì)節(jié)分析
- FROM
對(duì)FROM的左邊的表和右邊的表數(shù)據(jù)進(jìn)行笛卡爾積(CROSS JOIN)運(yùn)算,產(chǎn)生虛表VT1。產(chǎn)生的虛表VT1將傳遞給下一步驟進(jìn)行運(yùn)算。
- ON過(guò)濾
對(duì)虛表VT1進(jìn)行ON篩選,符合條件的數(shù)據(jù)行被記錄在虛表VT2中。
- OUTER JOIN添加外部列
如果指定了 OUTER JOIN(比如LEFT JOIN、 RIGHT JOIN),【主表中未匹配的數(shù)據(jù)行】也會(huì)保留添加到虛擬表VT2 中,產(chǎn)生虛擬表VT3 。 如果FROM子句中包含兩個(gè)以上的表的話,那么就會(huì)對(duì)上一個(gè)JOIN連接產(chǎn)生的結(jié)果VT3和下一個(gè)表重復(fù)執(zhí)行步驟1~3這三個(gè)步驟,一直到處理完所有的表為止。
- WHERE
對(duì)虛擬表VT3 進(jìn)行WHERE條件過(guò)濾。只有符合的記錄才會(huì)被插入到虛擬表VT4中。
- GROUP BY
根據(jù)group by子句中的列,對(duì)VT4中的記錄進(jìn)行分組操作,產(chǎn)生虛擬表VT5 。
- HAVING
對(duì)虛擬表VT5應(yīng)用having過(guò)濾,符合的記錄會(huì)被插入到虛擬表VT6中。
- SELECT
這個(gè)子句對(duì)SELECT子句中的元素進(jìn)行處理,生成VT7表。
- DISTINCT
尋找VT7中的重復(fù)列,并刪掉,生成VT8。如果在查詢(xún)中指定了DISTINCT子句,則會(huì)創(chuàng)建一張內(nèi)存臨時(shí)表(如果內(nèi)存放不下,就需要存放在硬盤(pán)了)。這張臨時(shí)表的表結(jié)構(gòu)和上一步產(chǎn)生的虛擬表VT7是一樣的,不同的是對(duì)進(jìn)行DISTINCT操作的列增加了一個(gè)唯一索引,以此來(lái)除重復(fù)數(shù)據(jù)。
- ORDER BY
從VT8中的表中,根據(jù)ORDER BY 子句的條件對(duì)結(jié)果進(jìn)行排序,生成VT9表。
- LIMIT
LIMIT子句從上一步得到的 VT9虛擬表 中選出從指定位置開(kāi)始的指定行數(shù)據(jù)。
總結(jié)
- 魚(yú)骨圖
網(wǎng)上有人將SQL解析順序用圖表表示,很像一條魚(yú)骨,也很形象

SQL語(yǔ)句解析順序
- 流程分析
每個(gè)步驟中,都會(huì)產(chǎn)生一個(gè)虛表記錄過(guò)濾后的數(shù)據(jù)結(jié)果集,然后將傳遞給下一步驟進(jìn)行運(yùn)算。
1. FROM(將最近的兩張表,進(jìn)行笛卡爾積)---VT1
2. ON(將VT1按照它的條件進(jìn)行過(guò)濾)---VT2
3. LEFT|RIGHT JOIN(保留主表的記錄)---VT3
4. WHERE(過(guò)濾VT3中的記錄)--VT4…VTn
5. GROUP BY(對(duì)VT4的記錄進(jìn)行分組)---VT5
6. HAVING(對(duì)VT5中的記錄進(jìn)行過(guò)濾)---VT6
7. SELECT(對(duì)VT6中的記錄,選取指定的列)--VT7
8. DISTINCT (尋找VT7中的重復(fù)列,并刪掉)--VT8
9. ORDER BY(對(duì)VT8的記錄進(jìn)行排序)--VT9
10. LIMIT(對(duì)排序之后的值進(jìn)行分頁(yè))--MySQL特有的語(yǔ)法
- WHERE條件解析順序
MySQL :從左往右去執(zhí)行WHERE條件的。
Oracle :從右往左去執(zhí)行WHERE條件的。