MS SQL Server 2005 物理查詢處理中的各個(gè)階段(二)
大家好,我是浪客,和大家分享一些最近我從《Microsoft SQL SERVER 2005技術(shù)內(nèi)幕:T-SQL查詢》書中的心得,終于出“二“了,回應(yīng)很多朋友的需求,今天抽空寫了物理查詢階段,
上文中你真的了解“T-SQL邏輯查詢嗎?”提到的這種搜索方式,也許很多人不明白(包括我,我看之前簡直感到詫異),很多都想 如果表的記錄有10000000~!#!@條,那每次的CROSS JOIN 將會(huì)長生 m*n的記錄,我們就假設(shè)是1W條 1w的平方還是有點(diǎn)點(diǎn)恐怖的,所以實(shí)際存儲(chǔ)引擎并不是如此查詢的,但是講清楚 邏輯查詢很重要,因?yàn)槟鞘俏锢聿樵兊幕A(chǔ),我覺得 理解數(shù)據(jù)庫引擎的查詢處理方式有助于 開發(fā)人員在生產(chǎn)過程中做出正確的選擇。PS:(有朋友說文章很多都“借鑒“別人的例子,我想是好東西用什么例子都不重要吧,只要能分享給大家,我抄都抄過來,再說是我對(duì)書的一些總結(jié),呵呵~,這里要感謝作者Lubor Kollar,他是書中該章節(jié)的作者,是MS SQL SERVER 2005開發(fā)人員)。
那么開始吧,當(dāng)一個(gè)查詢你到達(dá)數(shù)據(jù)庫引擎的時(shí)候 ,SQL SERVER 執(zhí)行兩個(gè)主要的步驟來產(chǎn)生結(jié)果,一步就是 “查詢編譯”,一個(gè)是“生成查詢計(jì)劃”。首先提一下為什么存儲(chǔ)過程的效率總是比應(yīng)用程序級(jí)別的T-SQL語句來的更迅速,首先拋開網(wǎng)絡(luò)傳輸T-SQL語句的時(shí)間不管,我們利用應(yīng)用程序發(fā)送的T-SQL語句,交個(gè)數(shù)據(jù)庫執(zhí)行,他首先就要對(duì)T-SQL語句進(jìn)行編譯,在SQL中編譯的概念,和我們寫應(yīng)用程序理解應(yīng)該是一致的,包括語法的檢查,代數(shù)化以及查詢優(yōu)化,就像我們的應(yīng)用程序(我是搞.NET的),編譯器對(duì)你的C#代碼進(jìn)行編譯,先檢查語法的錯(cuò)誤,然后生成dll,dll 中就包括對(duì)整個(gè)類庫的描述類似于SQL中的執(zhí)行計(jì)劃,回到SQL中,這個(gè)編譯過程當(dāng)然是需要時(shí)間的,所以應(yīng)用程序級(jí)別的T-SQL 交給數(shù)據(jù)庫編譯以后才執(zhí)行,更可惡的是,竟然對(duì)外部傳輸來的T-SQL語句不會(huì)進(jìn)行 “過程緩存”,因?yàn)樗诰幾g后就立即執(zhí)行了,而存儲(chǔ)過程他就已經(jīng)預(yù)先編譯了,也進(jìn)行了查詢的優(yōu)化了,還會(huì)保存在“過程緩存”中,所以推薦使用存儲(chǔ)過程。
下面就來展示一個(gè)例子:
USE Northwind;
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='London'
GROUP BY C.CustomerId
HAVING COUNT(o.OrderId)>5
ORDER BY NumOrders;
返回結(jié)果:
EASTC 8
SEVES 9
BSBEV 10
AROUT 13
上次 就有朋友在留言中提到這個(gè)問題 ,下面我們來看看他的執(zhí)行計(jì)劃,到底 邏輯處理 和物理處理 有什么不同.我們點(diǎn)擊 “顯示估計(jì)的執(zhí)行計(jì)劃” ,然后找到 最右邊的 Index seek 索引查找,下圖
這是我切下來的圖片,
我們看到 他的Seek 謂詞 是 [Northwind].[dbo].[Customers].City=N’London’
再看看 我們的查詢 語句的WHERE 部分
WHERE c.City='London'
完全 符合我在 你真的了解T-SQL邏輯查詢嗎? 一問中先說到的 第一個(gè)階段 找到FROM 的表,但是又有一點(diǎn)不同,物理查詢 他會(huì)等到執(zhí)行CROSS 鏈接以后的 記錄,他會(huì)先直接 篩選WHERE 中的記錄 等于 講 前3個(gè) 邏輯 處理階段 的 連接和 第4個(gè)階段WHERE 合并了.至于 這樣有什么好處呢?
我們繼續(xù),首先我們分析 WHERE ,我們先考慮一種情況 如果 是按照 邏輯 執(zhí)行階段的順序,CROSS JOIN 下來的 虛擬表 將是非常恐怖的 .可是 MS 的員工 在邏輯階段 到物理階段的過程中,肯定會(huì)采取一些列手段來優(yōu)化T-SQL 語句,所以 我們聯(lián)想到 先執(zhí)行WHERE 中的 邏輯處理階段 將 左表中的 結(jié)果 返回
相當(dāng)于 執(zhí)行:
USE Northwind;
SELECT C.CustomerId
FROM dbo.Customers AS C
WHERE c.City='London'
他返回的結(jié)果是:
AROUT
BSBEV
CONSH
EASTC
NORTS
SEVES
果然和我們 預(yù)想的一樣返回的 行數(shù) 完全和執(zhí)行計(jì)劃中的 估計(jì)行數(shù) : 6 行 吻合,
這樣執(zhí)行的結(jié)果的好處 ,我們自然可以聯(lián)想到,將6行的結(jié)果集 再來 CROSS JOIN 就小多了
,下面我們繼續(xù)剛才的分析,接著 自然是 Orders 表的鏈接,
自然 就
我們?cè)倩剡^來看看 之前說的 物理處理階段,是不是 完全吻合. 之所以要說明白 邏輯階段,(說個(gè)題外話,有興趣的朋友可以去看看Algebrizer,他是T-SQL中的 新組件是 綁定的重要功能,我想對(duì)高數(shù)有研究的朋友可能會(huì)喜歡里面的研究和分析.他取代了2000中的Normalizer組件,在物理 邏輯 級(jí)別提高了T-SQL 效率.)
對(duì)于 后面文章的 優(yōu)化查詢語句 起到了 舉足輕重的作用,在 講明了 物理 處理階段和 邏輯處理階段 對(duì)于 存儲(chǔ)引擎是 怎么執(zhí)行T-SQL的 有了一定的了解,才能從原理級(jí)別去提高T-SQL ,這也是國內(nèi)很多同行不曾重視的.當(dāng)然本文的下一篇將繼續(xù)我們的研究 -子查詢的精要