這篇文章主要和大家討論幾乎所有人都熟悉,但不少人又陌生的一條select語句。不知道大家有沒有想過到底是什麼東西讓SQLServer能理解我們寫的select。這中間到底發生了什麼,是不是有過衝動想去瞭解。至少我曾經衝動想去瞭解,但當時主要在研究CLR以及webform相關知識。後來主要精力放在研究SQLserver內部機制,今天就給大家介紹下這條語句。
一、範例資料庫指令碼
create database Test
go
alter database Test set recovery simple
go
use Test
go
create table Test
(
ID int identity(1,1) primary key,
[Name] varchar(64) not null default '',
CreatedTime datetime not null default getdate()
)
insert into Test([name]) values('xiaojun')
這個指令碼就不介紹了,很簡單。
二、語句分析
select * from Test
簡單吧,本來嘛標題就是之簡單語句。下面開始分析這條語句吧,假設讀者已經知道了SQLServer整體架構或者已經閱讀過這個系列第一篇文章。當這條語句被可靠的傳遞到關聯式引擎中的命令分析器,接下來就發生了:
分析:從文法庫中檢查T-SQL進行基本的語法檢查。如果文法出錯了,那整個語句就立即停止,提示使用者文法出錯,哪出錯。比如錯誤使用的關鍵字、列、表名等。如果文法沒有出錯,就會產生一個分析樹傳遞給下一個步驟。
綁定:1、名字解析:檢查所有的對象在使用者的安全上下文中存在並可見。這個步驟很好理解主要是資料庫每個對象都有許可權。如果登入的帳號沒有相應許可權,就結束這個步驟。
2、類型推導:確定解析樹中每個節點的最終類型。這個步驟主要是補充分析分析步驟中的分析樹,確定其最終的類型。不知道大家可想過為什麼要到這一步才確定。為什麼不在分析中確定呢?主要原因是效率,類型推導會消耗資源,沒有必要在沒有確定使用者對每個對象有許可權的情況下確定。那為什麼不直接先確定使用者對每個對象有許可權再做分析呢。那是因為沒做分析的時候,系統無法知道具體有哪些對象。我又要說了,SQLServer的設計真的可以說是很精緻的,連這樣的細節和資源消耗都考慮了。值得我們學習哦。
3、彙總綁定:確定哪些地方可以進行彙總。這個步驟主要和SQL中是否有彙總操作有關係。
4、組合綁定:將彙總綁定到正確的挑選清單中。這個步驟是把彙總操作與需要彙總的資料行繫結對應起來。
這兩步操作主要是由命令分析器完成,它最終得到分析樹,傳遞給SQLServer引擎中最複雜最優技術含量的組件,沒有之一,查詢最佳化工具。查詢最佳化工具功能概況起來很簡單,就是最佳化SQL。具體最佳化模型如下:
最佳化:1、檢查執行計畫緩衝中是有沒對應的執行計畫。 如果沒有,繼續下面操作。如果有則使用緩衝。SQLServer是根據SQL的雜湊值比較的。想想為什嗎?
2、預最佳化:查詢語句很簡單,開銷足夠小,直接結束最佳化。比如沒有聯結的基本查詢。屬於零開銷,稱為普通計劃。比如我們這的select語句預最佳化就搞定了。
3、階段0:檢驗基本規則,以及散列和嵌套聯結選項。這個計劃的開銷是否小於0.2,如果是,結束最佳化。這裡的0.2以及下面的1.0,這是SQLServer內部的開銷值,僅供SQLServer系統內部使用。
4、階段1:檢驗更多的規則,以及變換聯結的順序。如果開銷最小的計劃的開銷小於1.0,如果是,結束最佳化。如果不是,繼續判斷。如果maxdop>0且這個系統是SMP系統,以及最小開銷大於並行化的開銷臨界值,則使用並行計劃。比較並行計劃的開銷和最好的串列計劃的開銷,將開銷更小的計劃傳遞給階段2。
並行計劃是指最佳化器根據情況,將恰當的操作符拆分為數個可以同步啟動並執行進程在不同的處理器上運行,需要多核支援。對於大資料量查詢可以提高效率。
maxdop是什麼呢?這是SQLServer的一個進階配置。我們可以通過sp_configure查看。如:
可能你直接運行sp_configure,看不到這個配置。主要是這是個進階配置項,預設不開啟。你運行以下語句後再運行sp_configure就能看到以中資訊。
sp_configure 'show advanced options',1
reconfigure
這裡面的進階配置值,預設情況下不需要修改。必須你對SQLServer有較深理解,以及在修改前做好修改對整個SQLServer的影響的評估後才去改動。說說這個maxdop吧,這是說SQLServer在執行並行計劃的最大處理器數目,0代表由SQLServer決定。否則就是按照使用者指定的最大並行度。因此上面的maxdop>0且這個系統是SMP系統的意思就是當使用者修改了這個配置項,那麼執行器在評估開銷時要優先考慮使用者修改過的最大並行度小的系統開銷。SMP系統是對稱處理器體繫結構,基於Intel處理器的伺服器基本上都是SMP系統。在此不展開說。
不知道大家注意到沒,我上面的圖查詢最佳化工具輸出的是較好的執行計畫。想想為什嗎? 如果想查看最佳化過程的內部情況,可以使用一下sys.dm_exec_query_optimizer_info動態管理檢視。比如,下面示範證明我們這條select語句是屬於普通計劃。按照如下操作執行:
dbcc freeproccache --清空執行計畫緩衝
select * from sys.dm_exec_query_optimizer_info where counter in('optimizations','trivial plan','search 0','search 1','search 2')
結果如下:
繼續:
select * from Test
select * from sys.dm_exec_query_optimizer_info where counter in('optimizations','trivial plan','search 0','search 1','search 2')
結果如下:
發現了吧,trival plan類型計數+1,說明最佳化器對select * from Test進行最佳化時是普通計劃。
5、階段2:檢驗所有可能的計劃,並且選擇達到檢驗的時間限制時開銷最小的計劃。
執行:這個計劃被調度執行,這個涉及到SQLOS不在本篇文章討論範圍,只要先簡單理解為交給CPU執行。
三、結尾
其中這個語句還有很多地方可以分析,比較在這條語句執行時,加鎖以及如何被調度執行。這些還是希望在放在後面的章節中解釋。這篇文章主要是談到了SQLServer如何對SQL進行解析最佳化的。仔細研究,你會發現SQLServer的查詢最佳化工具做了很多最佳化措施當然其他資料庫也類似的組件。其實你會發現這些對於我們大部分開發人員都是屏蔽的。屏蔽是一種進步,java、.net的記憶體回收屏蔽了開發人員對記憶體的管理,那SQLServer在這裡屏蔽了什麼呢,這需要研究資料庫曆史。只有研究曆史,才能站在一個較高的角度知道現在的資料庫為什麼是現在的樣子。
今天分析就到此結束,文中如有描述不當的地方,歡迎指出。共同進步才是硬道理。
列下下一步六篇文章計劃 :
擦亮自己的眼睛去看SQLServer之曆史淵源
擦亮自己的眼睛去看SQLServer之數學基石
擦亮自己的眼睛去看SQLServer之簡單insert
擦亮自己的眼睛去看SQLServer之實用索引
擦亮自己的眼睛去看SQLServer之鎖機制
擦亮自己的眼睛去看SQLServer之糾結的Tempdb
......