mysql 中sql的執行順序


文章轉自 https://www.cnblogs.com/annsshadow/p/5037667.html

               https://www.cnblogs.com/yyjie/p/7788428.html

ql和mysql執行順序,發現內部機制是一樣的。最大區別是在別名的引用上。 

一、sql執行順序 
(1)from 
(3) join 
(2) on 
(4) where 
(5)group by(開始使用select中的別名,后面的語句中都可以使用)   這里可以使用表中普通字段的別名,不能使用聚合函數的別名
(6) avg,sum.... 
(7)having 
(8) select 
(9) distinct 
(10) order by 

從這個順序中我們不難發現,所有的 查詢語句都是從from開始執行的,在執行過程中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入。 
第一步:首先對from子句中的前兩個表執行一個笛卡爾乘積,此時生成虛擬表 vt1(選擇相對小的表做基礎表) 
第二步:接下來便是應用on篩選器,on 中的邏輯表達式將應用到 vt1 中的各個行,篩選出滿足on邏輯表達式的行,生成虛擬表 vt2 
第三步:如果是outer join 那么這一步就將添加外部行,left outer jion 就把左表在第二步中過濾的添加進來,如果是right outer join 那么就將右表在第二步中過濾掉的行添加進來,這樣生成虛擬表 vt3 
第四步:如果 from 子句中的表數目多余兩個表,那么就將vt3和第三個表連接從而計算笛卡爾乘積,生成虛擬表,該過程就是一個重復1-3的步驟,最終得到一個新的虛擬表 vt3。 
第五步:應用where篩選器,對上一步生產的虛擬表引用where篩選器,生成虛擬表vt4,在這有個比較重要的細節不得不說一下,對於包含outer join子句的查詢,就有一個讓人感到困惑的問題,到底在on篩選器還是用where篩選器指定邏輯表達式呢?on和where的最大區別在於,如果在on應用邏輯表達式那么在第三步outer join中還可以把移除的行再次添加回來,而where的移除的最終的。舉個簡單的例子,有一個學生表(班級,姓名)和一個成績表(姓名,成績),我現在需要返回一個x班級的全體同學的成績,但是這個班級有幾個學生缺考,也就是說在成績表中沒有記錄。為了得到我們預期的結果我們就需要在on子句指定學生和成績表的關系(學生.姓名=成績.姓名)那么我們是否發現在執行第二步的時候,對於沒有參加考試的學生記錄就不會出現在vt2中,因為他們被on的邏輯表達式過濾掉了,但是我們用left outer join就可以把左表(學生)中沒有參加考試的學生找回來,因為我們想返回的是x班級的所有學生,如果在on中應用學生.班級='x'的話,left outer join會把x班級的所有學生記錄找回(感謝網友康欽謀__康欽苗的指正),所以只能在where篩選器中應用學生.班級='x' 因為它的過濾是最終的。 
第六步:group by 子句將中的唯一的值組合成為一組,得到虛擬表vt5。如果應用了group by,那么后面的所有步驟都只能得到的vt5的列或者是聚合函數(count、sum、avg等)。原因在於最終的結果集中只為每個組包含一行。這一點請牢記。 
第七步:應用cube或者rollup選項,為vt5生成超組,生成vt6. 
第八步:應用having篩選器,生成vt7。having篩選器是第一個也是為唯一一個應用到已分組數據的篩選器。 
第九步:處理select子句。將vt7中的在select中出現的列篩選出來。生成vt8. 
第十步:應用distinct子句,vt8中移除相同的行,生成vt9。事實上如果應用了group by子句那么distinct是多余的,原因同樣在於,分組的時候是將列中唯一的值分成一組,同時只為每一組返回一行記錄,那么所以的記錄都將是不相同的。 
第十一步:應用order by子句。按照order_by_condition排序vt9,此時返回的一個游標,而不是虛擬表。sql是基於集合的理論的,集合不會預先對他的行排序,它只是成員的邏輯集合,成員的順序是無關緊要的。對表進行排序的查詢可以返回一個對象,這個對象包含特定的物理順序的邏輯組織。這個對象就叫游標。正因為返回值是游標,那么使用order by 子句查詢不能應用於表表達式。排序是很需要成本的,除非你必須要排序,否則最好不要指定order by,最后,在這一步中是第一個也是唯一一個可以使用select列表中別名的步驟。 
第十二步:應用top選項。此時才返回結果給請求者即用戶。 

二、mysql的執行順序 
SELECT語句定義 
一個完成的SELECT語句包含可選的幾個子句。SELECT語句的定義如下: 
SQL代碼 

 

<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語句執行順序 
SELECT語句中子句的執行順序與SELECT語句中子句的輸入順序是不一樣的,所以並不是從SELECT子句開始執行的,而是按照下面的順序執行: 
開始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->ORDER BY子句->SELECT子句->LIMIT子句->最終結果 
每個子句執行后都會產生一個中間結果,供接下來的子句使用,如果不存在某個子句,就跳過 
對比了一下,mysql和sql執行順序基本是一樣的, 標准順序的 SQL 語句為: 

 

select 考生姓名, max(總成績) as max總成績

from tb_Grade

where 考生姓名 is not null

group by 考生姓名

having max(總成績) > 600

order by max總成績

 在上面的示例中 SQL 語句的執行順序如下: 

   (1). 首先執行 FROM 子句, 從 tb_Grade 表組裝數據源的數據 

   (2). 執行 WHERE 子句, 篩選 tb_Grade 表中所有數據不為 NULL 的數據 

   (3). 執行 GROUP BY 子句, 把 tb_Grade 表按 "學生姓名" 列進行分組

           (注:這一步開始才可以使用select中的別名,他返回的是一個游標,而不是一個表,所以在where中不可以使用select中的別名,而having卻可以使用,感謝網友  zyt1369  提出這個問題)

   (4). 計算 max() 聚集函數, 按 "總成績" 求出總成績中最大的一些數值 

   (5). 執行 HAVING 子句, 篩選課程的總成績大於 600 分的. 

   (7). 執行 ORDER BY 子句, 把最后的結果按 "Max 成績" 進行排序. 

 

 

文章轉自  https://www.cnblogs.com/huminxxl/p/3149097.html

查詢語句中select from where group by having order by的執行順序
 
1.查詢中用到的關鍵詞主要包含六個,並且他們的順序依次為 
select--from--where--group by--having--order by 
 
其中select和from是必須的,其他關鍵詞是可選的,這六個關鍵詞的執行順序 
與sql語句的書寫順序並不是一樣的,而是按照下面的順序來執行 
from--where--group by--having--select--order by, 
from:需要從哪個數據表檢索數據 
where:過濾表中數據的條件 
group by:如何將上面過濾出的數據分組 
having:對上面已經分組的數據進行過濾的條件  
select:查看結果集中的哪個列,或列的計算結果 
order by :按照什么樣的順序來查看返回的數據 
 
2.from后面的表關聯,是自右向左解析的 
而where條件的解析順序是自下而上的。 
 
結論:在寫SQL文的時候,盡量把數據量大的表放在最右邊來進行關聯, 
而把能篩選出大量數據的條件放在where語句的最下面。
 
SQL Select語句完整的 執行順序【從DBMS使用者角度】: 
  1、from子句組裝來自不同數據源的數據; 
  2、where子句基於指定的條件對記錄行進行篩選; 
  3、group by子句將數據划分為多個分組; 
  4、使用聚集函數進行計算; 
  5、使用having子句篩選分組; 
  6、計算所有的表達式; 
  7、使用order by對結果集進行排序。 

SQL Select語句的 執行步驟【從DBMS實現者角度,這個對我們用戶意義不大】: 
  1)語法分析,分析語句的語法是否符合規范,衡量語句中各表達式的意義。 
  2) 語義分析,檢查語句中涉及的所有數據庫對象是否存在,且用戶有相應的權限。 
  3)視圖轉換,將涉及視圖的查詢語句轉換為相應的對基表查詢語句。 
  4)表達式轉換, 將復雜的 SQL 表達式轉換為較簡單的等效連接表達式。 
  5)選擇優化器,不同的優化器一般產生不同的“ 執行計划” 
  6)選擇連接方式, ORACLE 有三種連接方式,對多表連接 ORACLE 可選擇適當的連接方式。 
  7)選擇連接 順序, 對多表連接 ORACLE 選擇哪一對表先連接,選擇這兩表中哪個表做為源數據表。 
  8)選擇數據的搜索路徑,根據以上條件選擇合適的數據搜索路徑,如是選用全表搜索還是利用索引或是其他的方式。 
  9)運行“ 執行計划”。 
 
 
 
 

from 子句--執行順序為從后往前、從右到左
表名(最后面的那個表名為驅動表,執行順序為從后往前, 所以數據量較少的表盡量放后)

oracle 的解析器按照從右到左的順序處理,FROM 子句中的表名,FROM 子句中寫在最后的表(基礎表 driving table)將被最先處理,即最后的表為驅動表,在FROM 子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表。如果有3 個以上的表連接查詢, 那就需要選擇交叉表(intersection table)作為基礎表, 交叉表是指被其他表所引用的表

多表連接時,使用表的別名並把別名前綴於每個Column上。可以減少解析的時間並減少那些由Column 歧義引起的語法錯誤.

 

where子句--執行順序為自下而上、從右到左

ORACLE 采用自下而上從右到左的順序解析Where 子句,根據這個原理,表之間的連接必須寫在其他Where 條件之前, 可以過濾掉最大數量記錄的條件必須寫在Where 子句的末尾。

group by--執行順序從左往右分組

提高GROUP BY 語句的效率, 可以通過將不需要的記錄在GROUP BY 之前過濾掉。即在GROUP BY前使用WHERE來過慮,而盡量避免GROUP BY后再HAVING過濾。

having 子句----很耗資源,盡量少用

避免使用HAVING 子句, HAVING 只會在檢索出所有記錄之后才對結果集進行過濾. 這個處理需要排序,總計等操作.

如果能通過Where 子句在GROUP BY前限制記錄的數目,那就能減少這方面的開銷.
(非oracle 中)on、where、having 這三個都可以加條件的子句中,on 是最先執行,where 次之,having 最后,因為on 是先把不符合條件的記錄過濾后才進行統計,它就可以減少中間運算要處理的數據,按理說應該速度是最快的,

where 也應該比having 快點的,因為它過濾數據后才進行sum,在兩個表聯接時才用on 的,所以在一個表的時候,就剩下where 跟having比較了。

在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算字段,那它們的結果是一樣的,只是where 可以使用rushmore 技術,而having 就不能,在速度上后者要慢。
如果要涉及到計算的字段,就表示在沒計算之前,這個字段的值是不確定的,where 的作用時間是在計算之前就完成的,而having 就是在計算后才起作用的,所以在這種情況下,兩者的結果會不同。

在多表聯接查詢時,on 比where 更早起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表后,再由where 進行過濾,然后再計算,計算完后再由having 進行過濾。

由此可見,要想過濾條件起到正確的作用,首先要明白這個條件應該在什么時候起作用,然后再決定放在那里。

 


select子句--少用*號,盡量取字段名稱

ORACLE 在解析的過程中, 會將依次轉換成所有的列名, 這個工作是通過查詢數據字典完成的, 使用列名意味着將減少消耗時間。

sql 語句用大寫的;因為 oracle 總是先解析 sql 語句,把小寫的字母轉換成大寫的再執行

 


order by子句--執行順序為從左到右排序,很耗資源

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM