首先作者給出了如下的sql查詢語句執行順序
() select () distinct () <top_specification> <select_list>
()from <left_table>
() <join_type> join <right_table>
() on <join _condition>
() where <where_condition>
()group by <group_by_list>
() with {cube|rollup}
()having(having_condition)
() order by <order_by_condition>
從這個順序中我們不難發現所有的 查詢語句都是從from開始執行的在執行過程中每個步驟都會為
下一個步驟生成一個虛擬表這個虛擬表將作為下一個執行步驟的輸入
第一步首先對from子句中的前兩個表執行一個笛卡爾乘積此時生成虛擬表 vt
第二步接下來便是應用on篩選器on 中的邏輯表達式將應用到 vt 中的各個行篩選出滿足on邏輯表達式的行生成虛擬表 vt
第三步如果是outer join 那麼這一步就將添加外部行left outer jion 就把左表在第二步中過濾的添加進來如果是right outer join 那麼就將右表在第二步中過濾掉的行添加進來這樣生成虛擬表 vt
第四步如果 from 子句中的表數目多余兩個表那麼就將vt和第三個表連接從而計算笛卡爾乘積生成虛擬表該過程就是一個重復的步驟最終得到一個新的虛擬表 vt
第五步應用where篩選器對上一步生產的虛擬表引用where篩選器生成虛擬表vt在這有個比較重要的細節不得不說一下對於包含outer join子句的查詢就有一個讓人感到困惑的問題到底在on篩選器還是用where篩選器指定邏輯表達式呢?on和where的最大區別在於如果在on應用邏輯表達式那麼在第三步outer join中還可以把移除的行再次添加回來而where的移除的最終的
舉個簡單的例子有一個學生表(班級姓名)和一個成績表(姓名成績)我現在需要返回一個x班級的全體同學的成績但是這個班級有幾個學生缺考也就是說在成績表中沒有記錄為了得到我們預期的結果我們就需要在on子句指定學生和成績表的關系(學生姓名=成績姓名)那麼我們是否發現在執行第二步的時候對於沒有參加考試的學生記錄就不會出現在vt中因為他們被on的邏輯表達式過濾掉了但是我們用left outer join就可以把左表(學生)中沒有參加考試的學生找回來因為我們想返回的是x班級的所有學生如果在on中應用學生班級=x的話那麼在left outer join 中就會將不會把x班級的學生的所有記錄找回來所以只能在where篩選器中應用 學生班級=x 應為它的過濾是最終的
第六步group by 子句將中的唯一的值組合成為一組得到虛擬表vt如果應用了group by那麼後面的所有步驟都只能得到的vt的列或者是聚合函數(countsumavg等)原因在於最終的結果集中只為每個組包含一行這一點請牢記
第七步應用cube或者rollup選項為vt生成超組生成vt
第八步應用having篩選器生成vthaving篩選器是第一個也是為唯一一個應用到已分組數據的篩選器
第九步處理select列表將vt中的在select中出現的列篩選出來生成vt
第十步應用distinct子句vt中移除相同的行生成vt事實上如果應用了group by子句那麼distinct是多余的原因同樣在於分組的時候是將列中唯一的值分成一組同時只為每一組返回一行記錄那麼所以的記錄都將是不相同的
第十一步應用order by子句按照order_by_condition排序vt此時返回的一個游標而不是虛擬表sql是基於集合的理論的集合不會預先對他的行排序它只是成員的邏輯集合成員的順序是無關緊要的對表進行排序的查詢可以返回一個對象這個對象包含特定的物理順序的邏輯組織這個對象就叫游標正因為返回值是游標那麼使用order by 子句查詢不能應用於表表達式排序是很需要成本的除非你必須要排序否則最好不要指定order by最後在這一步中是第一個也是唯一一個可以使用select列表中別名的步驟
第十二步應用top選項此時才返回結果給請求者即用戶到此為止我們將一個sql查詢語句的邏輯執行過程梳理了一遍對於使用查詢語句多年的我來說無疑對以前的不少問題得出了解答希望你也能從中受益我將在後面介紹sqlserver 中新加入的邏輯處理階段
From:http://tw.wingwit.com/Article/program/SQL/201311/16406.html