概念簡介
我們平時所說的查詢在SQLServer 中主要有兩部分來實現:
- 編譯查詢,主要包括了五個環節(緩存查找、分析、代數化、優化、緩存新計划)
流程描述: 首先,在計划緩存中查找是否包含新的查詢,如果包含則直接交由執行引擎來執行該緩存計划,跳過編譯階段。
其次,如果沒有匹配則執行分析階段(包括參數化、並將SQL文本轉化成邏輯樹作為下一個階段的輸入),
再次檢查緩存后是否包含,包含則交給執行引擎,否則繼續下一步。
第三,代數化。
第四,優化並將新計划交給執行引擎。
這里需要有個概念的介紹:執行計划緩存,
SQL Server 有一個用於存儲執行計划和數據緩沖區的內存池。池內分配給執行計划或數據緩沖區的百分比隨系統狀態動態波動。
內存池中用於存儲執行計划的部分稱為過程緩存。
執行計划緩存主要包含了查詢計划和執行上下文。
2. 執行查詢計划(生成執行計划--產生查詢結果),在下一篇中介紹。
編譯和重新編譯
SQL Server 有一個高效的算法,可查找用於任何特定 SQL 語句的現有執行計划。SQL Server 將重新使用找到的任何現有計划,從而節省重新編譯 SQL 語句的開銷。如果沒有現有執行計划,SQL Server 將為查詢生成新的執行計划。由此我們要做的就是如何高效的應用執行計划的緩存,又在合適重新編譯執行計划,來提高查詢效率,減少性能的損耗。
首先我們要知道什么情況下會有重新編譯產生新的執行計划,我簡單總結了幾種比較常見的情況:
1.使用WITH REPCOMPILE 或者調用sp_repcompile,將不會緩存計划。
2.架構的變更比如表或試圖中添加索引,增加或者刪除列等。
如圖,當執行架構名稱不同的時候會引發重新編譯,執行計划緩存不能復用,這個問題需要開發人員注意,經常會有不自覺添加或者減少架構名稱的舉動。不僅會影響性能,當服務器間移動代碼時會引起太多問題,建議使用schema.object(dbo.ExcutionTest)這樣的統一規范。
如果是增刪索引的話,根據實際情況會生成完全不同的執行計划。如圖:
建立索引后有表掃描變為了索引查找,這部分內容我在聚集索引的章節已經有過介紹這里就不詳細展開了。
3.SET選項,包括:ANSI_NULLS\ANSI_WARNINGS\CURSOR_CLOSE_ON_COMMIT_INPLICIT_TRANSACTIONS\ANSI_PADDING\QUOTED_IDENTIFIER,這些選項狀態的變化,會引起執行計划的重新編譯。建議,盡量采用數據庫默認的設置,不要在存儲過程中假如不必要的set選項。
4.根據計划的優化程度:如果對鍵的大量更改(對由查詢引用的表使用 INSERT 、UPDATE或 DELETE 語句所產生的修改)。
分析、代數化和優化
1.分析,會將SQL文本轉換為邏輯樹,為每一個語句創建邏輯樹。
2.代數化,主要完成檢查語義是否正確。
同時還會完成三個任務:
- 名稱解析:查詢每個對象的名稱是否存在正確,作用域是否可見;
- 類型派生:在分析樹種各節點的字段類型等,如表鏈接后的字段類型。
- 聚集綁定:根據語法判定聚集的實際操作在宿主查詢中。
- 分組綁定:驗證group by 語法是否正確(select 后面的非聚集列必須是group by后面的)。
3.優化
查詢優化是處理查詢中最復雜部分,這部分由系統自動完成,如果說前面的環節告訴我們“做什么”,那么優化器就是描述“如何做”,查詢優化器希望盡可能選擇高效的執行計划。這部分將在本系列最后做一個專題。詳細的闡述這里現提出流程(簡化--探索--實現)。
總結:
本篇系統的介紹了編譯查詢的流程,以及產生緩存、復用緩存、重新編譯等具體內容。對於優化我們的T-SQL語句來說有不少值得注意的地方,執行計划緩存的命中越多相應的我們的查詢消耗也就越低,但是這種情況也不是絕對的。最后附加一個用於重新編譯的工具和命令的超鏈接,里面有不少便於查詢分析執行計划是否高效甚至存在問題功能和方法,http://www.cnblogs.com/wenBlog/p/4966991.html。