淺談SQL SERVER 2000 T-SQL 的運行
T-SQL(Trantsact-SQL)是微軟公司在SYBASE的基礎上發展起來的一種結構化查詢語言 (SQL),是應用程式和預存程序與SQL SERVER通訊和訪問的工具.包涵了ANSI89和ANSI92標準.所以T-SQL不是一種標準的程式設計語言,它必須通過SQL SERVER的資料引擎來分析和運行,SQL SERVER是如何編譯和運行T-SQL語句呢?
SQL SERVER在處理任何T-SQL語句時都經過下面三個步驟:
1. 解析T-SQL語句
2. 編譯T-SQL語句
3. 執行T-SQL語句
當一個T-SQL的批處理提交到SQL SERVER伺服器,伺服器回將這個T-SQL批處理作為一個整體進行分析,在最佳化,編譯,最後在分步執行.
一. 解析
所謂”解析”是指SQL SERVER命令解析模組首先檢查T-SQL批處理文法的過程,如果沒有找到錯誤,命令解析器將原始碼細分為多個邏輯單元,比如:關鍵字,標識符以及運算子.然後命令解析器會構建一個內部結構,最後通過這個內部結構產生DDL操作或DDM操作所需要的詳細的步驟.如果該T-SQL批處理包涵一個查詢,那麼這個內部結構被成為查詢樹(QUERY TREE),如果該T-SQL批處理是一個過程,那麼這個內部查詢被成為順序樹(SEQUENCE TREE).
圖一:SQL SERVER的關聯式引擎部分
大家可以看出在圖一的左邊,主要是T-SQL的解析,編譯和查詢最佳化(Query Optimizer).這是SQL SERVER運行T-SQL非常關鍵的部分.在圖的右邊是動作項目,當T-SQL語句編譯過後就會直接傳給執行結構進行運行.在中間的部分是SQL管理器,控制整個T-SQL批處理的解析,編譯和執行. SQL Message 是從用戶端接受的(TDS)資料.Express Services Libary是進行資料轉換,過慮資料和進行計算和統計,同時也會格式化輸出的資料.
二.編譯
這一步主要是將順序樹(SEQUENCE TREE)產生為一個執行規劃, 查詢最佳化工具(Query Optimizer)主要是對T-SQL語句所要檢索的資源進行評估,產生I/O的時間,過慮時間和其他邏輯處理的時間.然後查詢最佳化工具(Query Optimizer)是試圖利用一個最小資源的方案.
這個方案中還包括執行是需要的工作清單(比如:安全檢查,約束檢查,觸發器檢查等等).這個就被成為執行規劃
三.執行
動作項目根據執行規劃在快取中運行並滯留,執行規劃的不同步驟將被發送到關聯式引擎的不同組件進行處理:DML管理器,DDL管理器,預存程序管理器,交易處理管理器和工具 + 生產力管理器.處理結果將以結果集的方式被收集合并返回調用者.
執行規劃將在快取中被保留一段時間,如果同一使用者或其他使用者發出類似請求的T-SQL批處理,關係資料引擎將會優先在快取中尋找匹配的執行規劃.如果該執行規劃存在就採用運行,如果不存在,SQL SERVER 就會解析並編譯這個T-SQL批處理.
如果SQL SERVER需要的記憶體不夠,它會從記憶體中刪除一些執行規劃.SQL SERVER有一個很好的”老化”演算法,它可以統計某個執行規劃的使用時間和次數.如果記憶體足夠的大,也可以無限的增加執行規划到記憶體中.
四. 簡單查詢執行規劃的重用
簡單T-SQL批處理只可以在2中情況下被重用:
1. 第二次查詢的文本必須和快取中執行規劃所描述的文本完全相同,每一項都要匹配,包括:空格,換行,縮排,在大小寫敏感的SQL SERVER中還包括字元的大小寫.
2. 查詢包涵完全修飾的資料庫物件以便重用執行規劃.
SELECT * FORM PUBS.DBO.SALES
所以在這種情況下:”*” 的執行效率要高於SELECT COLUMN_LIST FROM TABLENAME的語句.
五.預存程序執行規劃的重用:
預存程序比簡單查詢執行效率高的一個主要原因是:預存程序的執行規劃可以方便的被重用.比圖:在執行一個簡單查詢3次,那麼SQL SERVER需要執行3次解析—編譯—執行的過程,而預存程序最有可能的是在第一次執行之前被解析並被重新編譯一次.
預存程序的執行規劃分2部分:
1. 可重新進入部分,可以被人員數量的預存程序同時使用;
2. 包括資料內容的部分,也就是執行期間預存程序的各個參數;
在SQL SERVER中有一個組件--惰性寫入器(LAZYWRITER),來判斷緩衝中的執行規劃是否會重用和是否需要申請更多的記憶體.如果有下列的操作,SQL SERVER將立即重緩衝中刪除執行規劃,釋放記憶體:
l 明顯改變資料量;
l 建立和刪除INDEX;
l 添加和更改約束;
l 更改INDEX的分布資訊;
l 顯示的調用sp_recompile以重新編譯預存程序或觸發器;
當SQL SERVER建立一個執行規劃就會給該執行規劃一個”編譯成本因子”.這個成本因子的值取決於建立該執行規劃所需要的資源開銷.例如:賦予一個大型的執行規劃的編譯成本因子是8,而一個小的執行規劃的編譯成本因子是2.每次某個CLIENT引用該執行規劃,他的”年齡”就會遞增一個編譯成本因子的值.
SQL SERVER的惰性寫入器(LAZYWRITER)是如何工作的呢? SQL SERVER的惰性寫入器用來降低執行規劃的”年齡”, 惰性寫入器進程會定期迴圈遍曆快取中的所有執行規劃,並將執行規劃的”年齡”減1,當執行規劃的編譯成本因子的值為0時,SQL SERVER就會收回分配給該執行規劃的記憶體.
備忘:
SQL SERVER的最佳化組件(Query Optimizer)會在預存程序引用的表資料更新時自動重新編譯該預存程序,更新執行規劃.但在你添加一個INDEX時,SQL SERVER不會自動重新編譯預存程序,需要手動重新整理快取的執行規劃(最簡單的方法,你可以重新啟動MSSQLSERVER服務),這是該預存程序會被重新編譯,或者你可以手動強制重新編譯:
Exec sp_recompile sp_storedprocedurename
SQL SERVER還提供了另外一種高效的重新編譯的方法:如果有大量的預存程序和觸發器引用某一個表,並且還添加表INDEX以提高檢索的效率.這是我們可以通過重新編譯這個表來重新編譯所有的預存程序和觸發器:
EXEC sp_compile tablename.
所有我們在重建立立索引或執行了更新索引的操作子後,一定要重新編譯預存程序,不過這是最好的辦法是重新啟動伺服器.