MySQL中SQL的執(zhí)行順序詳解
MySQL中SQL的執(zhí)行順序
在日常的開發(fā)工作中,我們經常會自己手寫一些sql語句,但是對于這些sql語句是怎么執(zhí)行的,執(zhí)行的順序又是怎么樣的呢?想必各位大佬對此也是了解的,所以對sql語言的執(zhí)行順序有一定的了解的話,會更好的理解一些sql語句,從而更好的寫sql語句,也有助于SQL的調優(yōu)。就比如說,先使用子查詢對數(shù)據(jù)進行過濾后在進行join操作還是直接使用join操作之后,再進行數(shù)據(jù)過濾。
SQL執(zhí)行順序
下面是一條我們經常會用到也經常會手寫的一條sql語句。
select distinct 查詢列表(要查的字段), max(), avg().... 聚合函數(shù) from 左邊的表們s 連接類型(left|inner) join 右邊的表們s on 連接條件 where 篩選條件 group by 分組的列表(按什么字段分組) having having_condition order by 排序的字段 limit pageSize
下面是sql語句的執(zhí)行順序
語法格式 | 語法含義 | 執(zhí)行順序 |
---|---|---|
select | 查詢語句 | 8 |
distinct | 去重 | 9 |
sum(), avg()… | 聚合函數(shù) | 6 |
from tableA | 主表 | 1 |
join tableB | 連接 | 3 |
on | 連接條件 | 2 |
where | 過濾條件 | 4 |
group by | 分組 | 5 |
having | having條件 | 7 |
order by | 排序 | 10 |
limit | 分頁 | 11 |
查詢語句都是從from開始執(zhí)行的,在執(zhí)行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執(zhí)行步驟的輸入。
- 首先對from子句中的前兩個表執(zhí)行一個笛卡爾乘積,此時生成虛擬表 vt1(選擇相對小的表做基礎表)。
- 接下來便是應用on篩選器,on 中的邏輯表達式將應用到 vt1 中的各個行,篩選出滿足on邏輯表達式的行,生成虛擬表 vt2 。
- 如果是outer join 那么這一步就將添加外部行,left outer jion 就把左表在第二步中過濾的添加進來,如果是right outer join 那么就將右表在第二步中過濾掉的行添加進來,這樣生成虛擬表 vt3 。
- 如果 from 子句中的表數(shù)目多余兩個表,那么就將vt3和第三個表連接從而計算笛卡爾乘積,生成虛擬表,該過程就是一個重復1-3的步驟,最終得到一個新的虛擬表 vt3。
- 應用where篩選器,對上一步生產的虛擬表引用where篩選器,生成虛擬表vt4。
- 注意where與on的區(qū)別:先執(zhí)行on,后執(zhí)行where;on是建立關聯(lián)關系在生成臨時表時候執(zhí)行,where是在臨時表生成后對數(shù)據(jù)進行篩選的。
- group by 子句將中的唯一的值組合成為一組,得到虛擬表vt5。如果應用了group by,那么后面的所有步驟都只能得到的vt5的列或者是聚合函數(shù)(count、sum、avg等)。原因在于最終的結果集中只為每個組包含一行。這一點請牢記。
- 應用avg或者sum選項,為vt5生成超組,生成vt6.
- 應用having篩選器,生成vt7。having篩選器是第一個也是為唯一一個應用到已分組數(shù)據(jù)的篩選器。
- 處理select子句。將vt7中的在select中出現(xiàn)的列篩選出來。生成vt8.
- 應用distinct子句,對vt8進行去重,生成vt9。
- 應用order by子句。按照order_by_condition排序vt9,此時返回的一個游標,而不是虛擬表。
- 應用limit選項。生成vt10返回結果給請求者即用戶。
MySQL的執(zhí)行順序
SELECT語句定義
一個完整的SELECT語句包含可選的幾個子句。SELECT語句的定義如下:
<SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>]
SELECT子句是必選的,其它子句如WHERE子句、GROUP BY子句等是可選的。
一個SELECT語句中,子句的順序是固定的。例如GROUP BY子句不會位于WHERE子句的前面。
SELECT語句執(zhí)行順序
SELECT語句中子句的執(zhí)行順序與SELECT語句中子句的輸入順序是不一樣的,所以并不是從SELECT子句開始執(zhí)行的,而是按照下面的順序執(zhí)行:
開始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->SELECT子句->ORDER BY子句->LIMIT子句->最終結果
每個子句執(zhí)行后都會產生一個中間結果,供接下來的子句使用,如果不存在某個子句,就跳過
對比了一下,MySQL和sql執(zhí)行順序基本是一樣的, 標準順序的 SQL 語句為:
select empName, max(salary) as maxSalary from t_emp where empName is not null group by empName having max(salary) > 2000 order by maxSalary
在上面的示例中 SQL 語句的執(zhí)行順序如下:
(1). 首先執(zhí)行 FROM 子句, 從 t_emp 表組裝數(shù)據(jù)源的數(shù)據(jù)
(2). 執(zhí)行 WHERE 子句, 篩選 t_emp 表中所有數(shù)據(jù)不為 NULL 的數(shù)據(jù)
(3). 執(zhí)行 GROUP BY 子句, 把 t_emp 表按 empName 列進行分組
? (注:這一步開始才可以使用select中的別名,他返回一個游標,而不是一個表,所以在where中不可以使用select中的別名,而having卻可以使用)
(4). 計算 max() 聚集函數(shù), 按 maxSalary 求出總薪酬中最大的一些數(shù)值
(5). 執(zhí)行 HAVING 子句, 篩選員工的總薪酬大于 2000的.
(7). 執(zhí)行 ORDER BY 子句, 把最后的結果按 maxSalary 進行排序.
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
mysql5.7.42到mysql8.2.0的升級(rpm方式)
隨著數(shù)據(jù)量的增長和業(yè)務需求的變更,我們可能需要升級MySQL,本文主要介紹了mysql5.7.42到mysql8.2.0的升級(rpm方式),具有一定的參考價值,感興趣的可以了解一下2024-03-03解決MySQL添加新用戶-ERROR?1045?(28000)的問題
這篇文章主要介紹了MySQL添加新用戶-ERROR?1045?(28000)解決辦法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03