SQL Server調優系列進階篇(查詢優化器的運行方式)

前言html

前面咱們的幾篇文章介紹了一系列關於運算符的基礎介紹,以及各個運算符的優化方式和技巧。其中涵蓋:查看執行計劃的方式、幾種數據集經常使用的鏈接方式、聯合運算符方式、並行運算符等一系列的咱們常見的運算符。有興趣的童鞋能夠點擊查看。數據庫

本篇介紹在SQL Server中查詢優化器的工做方式,也就是一個好的執行計劃的造成,是如何評估出來的,做爲該系列的進階篇。緩存

廢話少說,開始本篇的正題。post

技術準備學習

數據庫版本爲SQL Server2008R2,利用微軟的一個更簡潔的案例庫(Northwind)進行分析。優化

 

正文內容url

在咱們將寫好的一個T-SQL語句拋給SQL Server準備執行的時候,首選要經歷的過程就是編譯過程,固然若是此語句之前在SQL Server中執行過,那麼將檢測是否存在已經緩存的編譯過的執行計劃,用以重用。spa

可是,執行編譯的過程須要執行一系列的優化過程,關於優化過程大體分爲兩個階段:code

一、首先,SQL Server對咱們寫的T-SQL語句先執行一些簡化,一般由查詢自己來尋找交互性及從新安排操做的順序。htm

在此過程當中,SQL Server側重於語句寫法調整,而不過多的考慮成本或者分析索引可用性的等,最重要的目標就是產生一個有效的查詢。

而後,SQL Server纔會加載元數據,包括索引的統計信息,進入第二個階段。

二、在這個階段纔是SQL Server一個複雜的優化過程,這個階段SQL Server會根據上一階段造成的執行計劃運算符進行評估和嘗試,甚至於重組執行計劃,因此相對這個優化過程是一個耗時的過程。

經過以下流程圖,來理解該過程:

這個圖看上去有點複雜,咱們來詳細分析下,其實就是將這個優化階段分爲3個子階段

<1>這個階段僅考慮串行計劃,也就說單處理器運行,若是這個階段找到了一個好的串行計劃,優化器就不會進入下一階段。因此對於數據量少的狀況,或者執行語句簡單的狀況下,基本採用的都是串行計劃。

固然,若是這個階段開銷比較大,那麼會進入到第2個階段,再進行優化。

<2>這個階段首先對第1階段的串行計劃進行優化,而後若是環境支持並行化操做,則進行並行化操做,經過進行比較,而後進行優化後的成本若是比較低則輸出執行計劃,若是成本仍是比較高,則進入第2階段,再繼續優化。

<3>其實到達這個階段就是優化的最後一個階段了,這個階段會對第2個階段中採用串行和並行的比較結果進行最後一步優化,若是串行執行好那就進一步優化,固然若是並行執行好的話,則再繼續並行優化。

其實第3階段是查詢優化器的無奈之舉,當到達第3階段了就是一個補救階段,只能最後作優化了,優化無缺很差的就只能按照這個執行計劃執行了。

那麼上述過程當中,各個階段的優化的原則有哪些:

關於這些優化器的最重要原則的就是:儘量的減小掃描範圍,不論是表或者索引,固然走索引比表好,索引的量也是越少越好,最理想的狀況是隻有一條或者幾條。 

因此,SQL Server也尊重上述原則,一直圍繞着這個原則去優化。

 

1、篩選條件分析

所謂的篩選條件,其實就是咱們所寫的T-SQL語句中的WHERE語句後面的條件,咱們會經過這裏面的語句進行儘可能縮小數據掃描範圍,SQL Server經過這些語句來優化。

通常格式以下:

column  operator  <constant or variable>

或者

<constant or variable>  operator  column

而這上面格式中operator包括:=、>、<、=>、<=、BETWEEN、LIKE

好比:name='liudehua'、price>4000、4000<price、name like 'liu%'、name='liudehua' AND price >1000

上面這些語句是咱們寫的語句中最經常使用的方式,而且這種方式也將被SQL Server用來減小掃描,而且這些列被索引覆蓋,那將盡可能採起索引進行獲取值,可是SQL Server也不是萬能的,有些寫法它也是不能識別的,也是咱們寫語句要避免的:

a、where name like '%liu'這貨就不能被SQL Server優化器識別,因此它只能經過全表掃描或者索引掃描執行。

b、name='liudehua' OR price >1000,這個一樣也是失效的,由於它不能利用兩個的篩選條件進行逐步減小掃描。

c、price+4>100這個一樣不被識別

d、name not in ('liudehua'、‘zhourunfa’),固然還有相似的:NOT 、NOT LIKE

舉個列子:

SELECT CustomerID FROM Orders
WHERE CustomerID='Vinet'

SELECT CustomerID FROM Orders
WHERE UPPER(CustomerID)='VINET'

因此上述的方式寫語句的時候須要儘可能避免,或者採起變通的方式實現。

 

2、索引優化

通過上面的篩選範圍的肯定以後,SQL Server緊接着開始索引的選擇,首先要肯定的第一件事就是篩選字段是否存在索引項,也就是說是否被索引覆蓋。

固然,若是查詢項爲索引覆蓋最好,若是不被索引覆蓋,那麼爲了充分利用索引的特性,就引入了書籤查找(bookmark)部分。

因此,鑑於此,咱們在建立索引的時候,所參考的屬性值就爲篩選條件的列了。

關於利用索引優化的選擇:

CREATE INDEX EmployeesName ON Employees(FirstName,LastName)
INCLUDE(HIREDATE) WITH(ONLINE=ON)
GO

SELECT FirstName,LastName,HireDate,EmployeeID 
FROM Employees
WHERE FirstName='Anne'

固然也不盡然只要查詢列存在索引覆蓋就執行索引查找,這取決於掃描的內容的多少,因此對於索引的利用程度還取決獲取內容的多少

來舉個例子:

CREATE INDEX NameIndex  ON person.contact(FirstName,LastName)
GO

SELECT * FROM Person.Contact
WHERE FirstName LIKE 'K%'

SELECT * FROM Person.Contact
WHERE FirstName LIKE 'Y%'
GO

徹底相同的查詢語句,來看執行計劃:

徹底相同的查詢語句,產生的查詢計劃徹底不一樣,一個是索引掃描,一個則是高效的索引查找。

這裏我只告訴你:FirstName like 'K%'的有1255行;而FirstName like 'Y%'只有37行,其中

其實,關於這裏的緣由就是統計信息在做怪了。

因此,特定的T-SQL語句不必定生成特定的查詢計劃,一樣特定的查詢計劃不必定是最優的方式,影響的它的因素不少:關於索引、關於硬件、關於表內容、關於統計信息等諸多因素影響。

關於統計信息這塊是大篇幅內容,咱們放在之後的篇幅中介紹,有興趣的能夠提早關注。

 

有問題能夠留言或者私信,隨時恭候有興趣的童鞋加入SQL SERVER的深刻研究。共同窗習,一塊兒進步。

 

文章最後給出前面幾篇的鏈接,如下內容基本涵蓋咱們平常中所寫的查詢運算的分解,看來有必要整理一篇目錄了.....

SQL Server調優系列基礎篇

SQL Server調優系列基礎篇(經常使用運算符總結)

SQL Server調優系列基礎篇(聯合運算符總結)

SQL Server調優系列基礎篇(並行運算總結)

SQL Server調優系列基礎篇(並行運算總結篇二)

SQL Server調優系列基礎篇(索引運算總結)

SQL Server調優系列基礎篇(子查詢運算總結) 

 

若是您看了本篇博客,以爲對您有所收穫,請不要吝嗇您的「推薦」。

相關文章
相關標籤/搜索