SQL語句的解析過程由于最近需要做一些sql query性能提升的研究,因此研究了一下sql語句的解決過程。在園子里看了下,大家寫了很多相關(guān)的文章,大家的側(cè)重點各有不同。本文是我在看了各種資 料后手機總結(jié)的,會詳細的,一步一步的講述一個sql語句的各個關(guān)鍵字的解析過程,歡迎大家互相學(xué)習。 SQL語句的解析順序簡單的說一個sql語句是按照如下的順序解析的:
客戶,訂單的查詢例子首先創(chuàng)建一個Customers表,插入如下數(shù)據(jù):
創(chuàng)建一個Orders表,插入如下數(shù)據(jù):
假如我們想要查詢來自Madrid的,訂單數(shù)小于3的客戶,并把他們的訂單數(shù)顯示出來,結(jié)果按照訂單數(shù)從小到大進行排序。 SELECT C.customerid, COUNT(O.orderid) AS numorders FROM dbo.Customers AS C LEFT OUTER JOIN dbo.Orders AS O ON C.customerid = O.customerid WHERE C.city = 'Madrid' GROUP BY C.customerid HAVING COUNT(O.orderid)< 3 ORDER BY numorders 查詢結(jié)果為:
下面我們會詳細的講述sql是怎樣計算出這個結(jié)果的:
FROM子句FROM子句標識了需要查詢的表,如果指定了表操作,會從左到右的處理,每一個基于一個或者兩個表的表操作都會返回一個輸出表。左邊表的輸出結(jié)果會作為下 一個表操作的輸入結(jié)果。例如,交表相關(guān)的操作有 (1-J1)笛卡爾積,(1-J2)ON過濾器,(1-J3)添加外部列。FROM句子生成虛擬表VT1。 Step 1-J1:執(zhí)行笛卡爾積(CROSS JOIN)笛卡爾積會把左右兩個表每一行所有可能的組合都列出來生成表VT1-J1,如果左表有m列,右表有n列,那么笛卡爾積之后生成的VT1-J1表將會有m×n列。 Step 1-J1這個步驟等價于執(zhí)行: SELECT * from Customers C CROSS JOIN Orders O 執(zhí)行結(jié)果為:(共有4×7列)
Step 1-J2:應(yīng)用ON過濾,(JOIN 條件)ON過濾條件是sql的三個過濾條件(ON,WHERE,HAVING)中最先執(zhí)行的,ON過濾條件應(yīng)用于前一步生成的虛擬表(VT1-J1),滿足ON過濾條件的行會被加入到虛擬表VT1-J2中。在應(yīng)用了ON 過濾之后,生成的VT1-J2表如下所示:
Step 1-J3:添加外部列這個步驟只會出現(xiàn)在使用了外連接的情況。對于外連接(LEFT,RIGHT, or FULL),你可以標記一個或者兩個表作為保留表。作為保留表意味著你希望這個表里面的所有列都被返回,即使它里面的數(shù)據(jù)不滿足ON子句的過濾條件。 LEFT OUTER JOIN 把左邊的表標記為保留表,RIGHTOUTER JOIN把右邊的表作為保留表,F(xiàn)ULL OUTER JOIN把兩個表都標記為保留表.Step 1-J3為根據(jù)VT1-J2中的虛擬表,添加了保留表中不滿足ON 條件的列,在未保留表中沒有對應(yīng)的列,因此標記為NULL。這個過程生成了虛擬表VT1-J3。
Step 2 WHERE 子句WHERE過濾被應(yīng)用到前一步生成的臨時表中,根據(jù)WHERE過濾條件生成臨時表VT2。
應(yīng)用這個過濾 WHERE C.city = 'Madrid' 這時生成的臨時表VT2的內(nèi)容如下:
在這個例子中,你需要在ON子句中使用ON C.customerid = O.customerid過濾,沒有訂單的客戶在1-J2這一步中被過濾掉,但是在1-J3這一步中作為外部列又被加回來。但是,由于你只想返回來自 Madrid的客戶,因此你需要在WHERE子句中過濾城市(WHERE C.city = ‘Madrid’),如果你放在ON過濾中,不屬于Madrid的客戶在添加外部列中會被添加回來。
Step 3 GROUP BY子句這個子句會把前一步中生成的臨時表中的數(shù)據(jù)進行分組,每一行都會分到并且只分到一個組里,生成虛擬表VT3。VT3表中包含了VT2表中所有的數(shù)據(jù),和分組標識符。 這是生成的臨時表VT3的內(nèi)容如下:
sql最終返回的結(jié)果中,每一個分組必須只能返回一行(除非被過濾掉),因此當一個sql語句中使用了GROUP BY時,在GROUP BY后面處理的子句,如SELECT,HAVING子句等,只能使用出現(xiàn)在GROUP BY后面的列,對于沒有出現(xiàn)GROUP BY后面的列必須使用聚合函數(shù)(如 MAX ,MIN,COUNT,AVG等),保證每一個GROUP只返回一行。 Step 4 HAVING子句HAVING子句用來過濾前一步生成的臨時表,并且只作用于分組后的數(shù)據(jù),滿足HAVING條件的GROUP被添加到虛擬表VT4中。 當應(yīng)用了這個過濾: HAVING COUNT(O.orderid) < 3 之后,生成的VT4表內(nèi)容如下:
Step 5 SELECT 子句盡管出現(xiàn)在sql語句的最前面,SELECT在第五步的時候才被處理,SELECT子句返回的表會最終返回給調(diào)用者。這個子句包含三個子階段:(5-1)計算表達式,(5-2) 處理DISTINCT,(5-3)應(yīng)用TOP過濾。 Step 5-1 計算表達式 SELECT子句中的表達式可以返回或者操作前一步表中返回的基本列。如果這個sql語句是一個聚合查詢,在Step 3之后,你只能使用GROUP BY中的列,對不屬于GROUP集合中的列必須使用聚合運算。不屬于FROM表中基本列的必須為其起一個別名,如YEAR(orderdate) AS orderyear。
在這個例子中: SELECT C.customerid, COUNT(O.orderid) AS numorders 結(jié)果會得到一個虛擬表VT5-1:
Step 5-2:應(yīng)用DISTINCT子句 如果sql語句中使用了DISTINCT,sql會把重復(fù)列去掉,生成虛擬表VT5-2。 Step 5-3:應(yīng)用TOP選項 TOP選項是T-SQL提供的一個功能,用來表示顯示多少行?;贠RDER BY子句定義的順序,指定個數(shù)的列會被查詢出來。這個過程生成虛擬表VT5-3。 正如上文提到的,這一步依賴于ORDER BY定義的順序來決定哪些列應(yīng)該顯示在前面。如果你沒有指定結(jié)果的ORDER BY順序,也沒有使用WITH TIES子句 ,每一次的返回結(jié)果可能會不一致。 在我們的例子中,Step 5-3被省略了,因為我們沒有使用TOP關(guān)鍵字。 Step 6:ORDER BY子句前一步返回的虛擬表在這一步被排序,根據(jù)ORDER BY子句指定的順序,返回游標VC6。ORDER BY子句也是唯一一個可以使用SELECT子句創(chuàng)建的別名的地方。
上面的步驟如圖所示:
本書中主要內(nèi)容是參照 Inside Microsoft SQL Server 2008:T-SQL Query,中的內(nèi)容,大家如果想深入了解sql查詢相關(guān)的知識,可以找這本書看看,我這有英文原版的pdf,需要的可以找我要。 |
|