SqlServer中Sql語句的邏輯執行順序


准備數據

Sql腳本如下,兩張表,一張客戶表Customers只包含customerid和city字段,一張訂單表Orders包含orderid和customerid(關聯Customers的customerid字段)

IF OBJECT_ID('dbo.Orders') IS NOT NULL DROP TABLE dbo.Orders;
IF OBJECT_ID('dbo.Customers') IS NOT NULL DROP TABLE dbo.Customers;
GO

CREATE TABLE dbo.Customers
(
  customerid  CHAR(5)     NOT NULL PRIMARY KEY,
  city        VARCHAR(10) NOT NULL
);

CREATE TABLE dbo.Orders
(
  orderid    INT     NOT NULL PRIMARY KEY,
  customerid CHAR(5)     NULL REFERENCES Customers(customerid)
);
GO

INSERT INTO dbo.Customers(customerid, city) VALUES('FISSA', 'Madrid');
INSERT INTO dbo.Customers(customerid, city) VALUES('FRNDO', 'Madrid');
INSERT INTO dbo.Customers(customerid, city) VALUES('KRLOS', 'Madrid');
INSERT INTO dbo.Customers(customerid, city) VALUES('MRPHS', 'Zion');

INSERT INTO dbo.Orders(orderid, customerid) VALUES(1, 'FRNDO');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(2, 'FRNDO');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(3, 'KRLOS');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(4, 'KRLOS');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(5, 'KRLOS');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(6, 'MRPHS');
INSERT INTO dbo.Orders(orderid, customerid) VALUES(7, NULL);
View Code

 

對於一條Sql語句(主要指的是查詢語句)的執行順序,很多開發人員並不是十分的了解,哪怕已經工作幾年的所謂高級開發人員也是一樣,對於他們來說,只關心最終得到的結果,並不關心中間的過程,那么了解SqlServer的語句執行過程到底有什么用處的?

1、如果不了解執行過程,下面的Sql語句你認為結果是一樣的嗎?

 

select * from Customers AS C
left join Orders AS O
On C.customerid=O.customerid
and C.customerid='FRNDO'
where city ='Madrid'


select * from Customers AS C
left join Orders AS O
On C.customerid=O.customerid
where city ='Madrid'
and C.customerid='FRNDO'

如果你了解Sql的執行順序,這個問題就不難解釋了,只不過是On語句和Where語句誰先執行以及On和Where之間是否還有其它執行步驟?

2、下面這兩條語句,第一個會提示列where語句中的myorder(select 中起的別名)無效,第二條是可以正常執行的,那問題來了,為什么order by語句中可以使用myorder列而where中就不可以呢?

select C.customerid,C.city,O.orderid as myorder 
from Customers AS C
left join Orders AS O
On C.customerid=O.customerid
where myorder >3
order by myorder desc


select C.customerid,C.city,O.orderid as myorder 
from Customers AS C
left join Orders AS O
On C.customerid=O.customerid
where O.orderid >3
order by myorder desc

Sql語句邏輯執行順序

一條常用的查詢語句應當是包含了下面的幾條命令

select distinct top 3  C.customerid, count(O.orderid) as orderCount 
from Customers as C
left join Orders as O 
ON C.customerid=O.customerid
where C.city='Madrid'
group by C.customerid
having count(O.orderid)>1
order by orderCount desc

 

1、From階段

From階段主要是標識數據來源,處理表運算符(join、apply,pivot等,本文只針對join講解),以及各個子階段(包括笛卡爾積、ON篩選器應用、添加外部行[只有外鏈接才有]);

1.1 join階段   join分為cross join、inner join、[left join、right join,full join]

                   cross join只是簡單的進行笛卡爾積,如上面的兩張表cross join之后的結果如下圖(左一);

                   inner join是在cross join的基礎上加入了ON篩選條件,如圖(左二和左三),只有ON(C.customerId=O.customerId)為Ture的才會返回

                   left join 是在 inner join的基礎上添加了外部行,在ON階段獲取的數據基礎上添加左表(Customer表)中的未滿足ON篩選條件的所有行(未在ON階段出現的),如圖(左四)

 

     

2、Where 階段

     where 階段就是對From階段得到的虛擬表進行進一步的過濾和篩選,和Join中的ON篩選類似,只是比ON篩選器執行的晚,特別對於外鏈接來說,ON篩選和Where篩選中間還多了一步添加外部行,這里應該可以解釋本文開篇提到的第一個問題了。

3、Group By

     Group By 只是按照指定的列名對第二步(如果存在)Where階段得到的虛擬表進行分組,每個分組只有一條數據,一般都是使用聚合函數來計算一些數據,比如上面例子中用按照CustomerId進行分組,用Count獲取每個客戶的訂單數量,然后按照訂單數量倒序去排名前三的客戶。

4、Having

     Having階段是在第三步(如果存在)分組之后再一次進行過濾,也就是對Group By階段得到的虛擬結果集進行進一步的篩選過濾,過程和ON、Where類似,只能用在Group BY 之后。

5、Select

     Select 階段則是針對第四步(如果存在)獲取的虛擬表的基礎上選擇需要的列,也就是最終要返回的列,看到這里是不是明白了本文開篇提到的第二個問題,為什么Select中的別名不能再Wher階段使用,因為Where早於Select,

Select又可以分為幾個子階段,包括(5.1計算表達式,5.2 Distinct,5.3 Top)

6、Order By

     Order By 階段是整個查詢的最后階段也就是根據指定的列名對Select階段進行排序,這也就是為什么在Order By語句中可以用Select階段起的別名的原因,不過Order By階段和上面的5個階段有個很大的區別,Order By階段返回的數據集是游標,而上面的5個階段生成的都是數據表,理解這點很重要,SqlServer的理論基礎是集合論,集合中的行之間沒有預先定義順序,它只是成員之間的邏輯組合,成員之間的順序無關緊要,而對於帶有Order By的查詢語句,是返回了一個按照特定的順尋組成的一個對象,成為游標。

最后附上一張Sql語句的執行流程圖(圖片來源Sql08解密)

總結

不知不覺已經寫了將近3個小時了,本文簡單介紹SqlServer中個語句的執行過程,只有理解的個語句的執行過程,才能寫出更加准確,更加高效的Sql命令。

 


免責聲明!

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



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