詳細講一講MySQL中Select語句的執(zhí)行順序
MySQL中關(guān)鍵字段的執(zhí)行順序
一句話概括MySQL數(shù)據(jù)庫中的select查詢語句各個子句的執(zhí)行順序:
from >> (xxx join) >> where > group by >> 聚合 >>having >> select>> order by >> limit ,union關(guān)鍵字的執(zhí)行順序是不定的,需要具體情況具體分析;
一個豐滿的SQL舉例
查詢語句都是從from開始執(zhí)行的,每個步驟都會為下一個步驟生成一個虛擬表:
(9) SELECT (10) DISTINCT <select_list>
(1) FROM <left_table> <right_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4).......join thirdTable on ......
(5) WHERE <where_condition>
(6) GROUP BY <group_by_list>
(7) WITH {CUBE|ROLLUP}
(8) HAVING <having_condition>
(11) ORDER BY <order_by_list>
(12) LIMIT <limit_number>
上述的SQL的查詢過程
1:from執(zhí)行from子句,前兩個表執(zhí)行第一個笛卡爾乘積,此時生成第一個虛擬表
什么是笛卡兒積?
當兩張表進行連接查詢,沒有任何條件限制的時候,最終查詢結(jié)果條數(shù),是兩張表條數(shù)的乘積,這種現(xiàn)象被稱為:笛卡爾積現(xiàn)象
2:上述形成的虛擬表各行基于on表達式進行篩選,留下符合的生成新的虛擬表
3:將在第二步中形成的虛擬表按照Left或者Right或者Outer關(guān)鍵字,這樣生成新的虛擬表
具體過程是這樣的
Left JOIN把左表記為基礎(chǔ)保留表,缺失的數(shù)據(jù)使用外部行的方式向虛擬表中進行插入,右表部分為Null,形成新的虛擬表
RIGHT JOIN把右表記為基礎(chǔ)保留表,缺失的數(shù)據(jù)使用外部行的方式向虛擬表中進行插入,左表部分為Null,形成新的虛擬表
4:超過兩表關(guān)聯(lián)的情況下,上述新生成的虛擬表和第三個表計算笛卡爾乘積,生成虛擬表,重復(fù)1-3的步驟,最終得到一個新的虛擬表
5:應(yīng)用where篩選器,對上一步生產(chǎn)的虛擬表引用where篩選器,進行最終的數(shù)據(jù)過濾,生成新的虛擬表;
6:group by后邊列中值一樣的歸為一組組合成為一組,得到新的虛擬表
7:應(yīng)用cube或者rollup選項,生成超組,執(zhí)行分組之后的聚合函數(shù),生成新的虛擬表
在這里就不難理解,為什么不能使用計算表達式或者別名進行分組,因為
8:having篩選已分組數(shù)據(jù),生成新的虛擬表
9:處理select子句,保留select后邊定義的列,生成新的虛擬表
10:應(yīng)用distinct子句,移除相同的行,生成新的虛擬表。
事實上如果應(yīng)用了group by子句那么distinct是多余的,原因同樣在于,分組的時候是將列中唯一的值分成一組,同時只為每一組返回一行記錄,那么所以的記錄都將是不相同的;
11:應(yīng)用order by子句,此時返回的一個游標,而不是虛擬表。
正因為返回值是游標,那么使用order by 子句查詢不能應(yīng)用于表表達式,排序是很需要成本的,除非你必須要排序,否則最好不要指定order by,在這一步中是第一個也是唯一一個可以使用select列表中別名的步驟。
12: Limit篩選返回的數(shù)據(jù)條數(shù)
對于包含outer join子句的查詢,到底在on篩選器還是用where篩選器指定邏輯表達式呢?
on和where的最大區(qū)別在于,如果在on應(yīng)用邏輯表達式那么在第三步outer join中還可以把移除的行再次添加回來,而where的移除的最終的;
Group函數(shù)的作用?
如果應(yīng)用了group by,那么后面的所有步驟都只能得到的某一列的第一行的值,或者是聚合函數(shù)(count、sum、avg等)
原因在于最終的結(jié)果集中只為每個組包含一行。這一點請牢記,如果某一行沒有使用聚集函數(shù),默認返回第一行
是先執(zhí)行g(shù)roup by還是先執(zhí)行select
通過上面的SQL順序執(zhí)行可知,先進行g(shù)roup by 在進行select
為什么group by和select同時使用時,select中的字段必須出現(xiàn)在group by后或者聚合函數(shù)中。
如何實現(xiàn)數(shù)據(jù)去重
在SQL中可以通過關(guān)鍵字distinct去重,也可以通過group by分組實現(xiàn)去重,但實際上,如果數(shù)據(jù)量很大的話,使用distinct去重的效率會很慢,使用Group by去重的效率會更高,而且,很多distinct關(guān)鍵字在很多數(shù)據(jù)庫中只支持對某個字段去重,無法實現(xiàn)對多個字段去重,如Postgresql數(shù)據(jù)庫。(測試數(shù)據(jù)300w+,使用distinct去重需要十幾秒,使用group by去重只需要幾秒)。
應(yīng)用HAVING過濾中可以使用聚合函數(shù)或者計算表達式或者別名進行過濾嗎?
執(zhí)行having的時候,已經(jīng)執(zhí)行過第六步的group by以及第七步的的聚合函數(shù)和計算表達式的以及別名。所以HAVING過濾中可以使用聚合函數(shù)或者計算表達式或者別名進行過濾嗎
SELECT * FROM customers c LEFT JOIN orders o ON c.customer_id = o.customer_id WHERE c.city='HangZhou' GROUP BY c.customer_id HAVING count(o.order_id) < 2;
哪些Column要放到Group by后邊呢?
這是一個表

select country ccc,max(count),concat(country,max(count)) bbb,1,concat(country,count) from coutry group by ccc,concat(country,count)
我們在Select后邊可以選擇的列包括:自然列,單純聚合函數(shù)、計算表達式(不含聚合函數(shù))、常量、計算表達式(聚合函數(shù))
其中:
- group by后邊可放可不放:常量
- group by必須放:自然列、計算表達式(不含聚合函數(shù))
- group by不允許放:聚合函數(shù)、計算表達式(包含聚合函數(shù))
注意:
單純使用case when的話,屬于計算表達式(不帶聚合函數(shù))如果使用group by的話,我們是必須和自然列一樣把他放到group by后邊的。
留一個問題:為什么select在order by之前,但是order by可以使用select后并不存在的列進行排序呢?
總結(jié)
到此這篇關(guān)于MySQL中Select語句執(zhí)行順序的文章就介紹到這了,更多相關(guān)MySQL Select語句執(zhí)行順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql 查詢當天、本周,本月,上一個月的數(shù)據(jù)
這篇文章主要介紹了mysql 查詢當天、本周,本月,上一個月的數(shù)據(jù)的sql代碼,在文中還給大家提到了mysql如何查詢當天信息,具體內(nèi)容詳情大家參考下本文2018-01-01
mysql5.7.14 解壓版安裝配置方法圖文教程(win10)
這篇文章主要為大家詳細介紹了win10下mysql5.7.14 winx64安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12
MySQL?SQL性能分析之慢查詢?nèi)罩?、explain使用詳解
這篇文章主要介紹了MySQL?SQL性能分析?慢查詢?nèi)罩?、explain使用,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04

