1. 程式人生 > >效能調優5:執行計劃

效能調優5:執行計劃

執行計劃的編譯和生成是很耗費資源和時間的,因此,SQL Server會把生成的任一執行計劃快取起來,以便重用。

一,快取機制

SQL Server使用特定的快取機制,以重用之前已經生成的執行計劃:

  • Ad hoc 查詢快取
  • 引數化Ad Hoc查詢快取
  • sys.sp_executesql 執行的查詢,是一種引數化的查詢語句
  • 儲存過程

前兩種機制是SQL Server自動進行的,使用者不能干預,而後兩種是使用者可以干預的。

1,Ad Hoc查詢快取

對於任意一個Ad Hoc查詢,SQL Server都會把它的執行計劃快取,只有當該批處理語句完全匹配該查詢時,才會複用已快取的執行計劃。

SQL Server根據批處理語句的文字計算出一個Hash值,對後續的Ad Hoc查詢的文字有計算Hash值,當兩個Hash值相同時,說明兩個批處理的文字完全一直,是同一個查詢,SQL Server優化器會複用已快取的執行計劃,如果Ad Hoc查詢的文字有任意一個字元變化(比如,大寫變小寫,不同的換行),都會導致計算出的Hash值不同,進而不能複用執行計劃。也就是說,Ad Hoc必須完全匹配才能複用。

2,引數化Ad-Hoc

SQL Server 自主決定是否把查詢中的常量作為引數來對待,除了常量不同之外,其他語句都相同,這就是一個查詢語句的模板,不同的引數使用相同的執行計劃。例如,對於以下兩個查詢語句,除了常量1和2不同之外,其他語句都相同,

select ID, Name from dbo.Users where ID=1
select ID, Name from dbo.Users where ID=2

SQL Server對該語句做引數化處理,得到模板,只要符合該模板,就複用已快取的執行計劃。

select ID, Name from dbo.Users where [email protected]

3,Prepared 查詢快取

使用者使用sys.sp_executesql 控制引數和模板,只要模板相同,而引數不同,都可以複用已快取的執行計劃。

4,儲存過程

使用者建立的儲存過程,在第一次執行時,編譯和生成執行計劃,並快取到計劃快取中,當下次呼叫相同的儲存過程,即使使傳遞的引數不同,SQL Server都會複用執行計劃。

二,引數嗅探

引數嗅探是指在建立儲存過程,或者引數化查詢的執行計劃時,根據傳入的引數進行預估並生成執行計劃。SQL Server生成的執行計劃對當前引數來說是最優的,而對其他大多數引數來說,是非常低效的。有些時候,針對一個查詢的第一次傳參,已經產生了一個執行計劃,當後續傳參時,由於存在對應引數的資料分佈等問題,導致原有的執行計劃無法高效地響應查詢請求,這就出現引數嗅探問題。

引數嗅探的本質是優化器根據引數來生成的執行計劃不是最優的,導致複用執行計劃時,查詢效能十分低下。對於引數嗅探問題,必須重新生成執行計劃,可以使用語句重編譯,編譯提示(optimize for)等功能來避免。

三,影響執行計劃複用的因素

SQL Server不會永久儲存計劃的快取,並且存在快取中的執行計劃也不會永久不變,每個計劃都會有一個Age值,當SQL Server探測到記憶體壓力時,會觸發Lazy Writer程序,用於清空所有的髒頁,釋放資料快取。當掃面到計劃快取時,會降低Age值,當複用一次計劃時,會增加Age值。當系統遇到記憶體壓力,或Age值降到0時,執行計劃會被移除記憶體。

除了這兩個條件之外,當遇到下面的條件時,執行計劃一會被移除記憶體,被重新編譯:

  • 查詢引用的基礎表的結構被更改
  • 查詢引用的索引被更改或被刪除
  • 查詢引用的統計資訊被更新
  • 執行計劃被強制重新編譯(詳見本問第四小節)
  • 單一查詢中混合了DDL和DML操作,也稱為延遲編譯
  • 在查詢中修改set選項
  • 查詢所用到的臨時表的結構被修改
  • 等等

在執行計劃執行過程中,執行計劃被重新編譯,是優化器根據表結構,索引結構和統計資訊做出優化的結構,目的是為了避免繼續使用不合適的執行計劃。

四,強制重新編譯執行計劃

修改儲存過程,觸發器等模組(Module)能夠使其執行計劃重新編譯,除此之外,還有其他方法,能夠強制重新編譯執行計劃

1,標記,下次重新編譯

使用該儲存過程,標記一個執行模組(SP,Trigger,User-Defined Function)在下次執行時,重新編譯執行計劃

sys.sp_recompile [ @objname = ] 'object'

2,不復用執行計劃

在建立儲存過程時,使用WITH RECOMPILE 選項,在每次執行SP時,都重新編譯,使用新的執行計劃。

CREATE PROCEDURE dbo.usp_procname 
    @Parameter_Name varchar(30) = 'Parameter_default_value'
WITH RECOMPILE

3,執行時重新編譯

在執行儲存過程時,重新編譯儲存過程的執行計劃

exec dbo.usp_procname @Parameter_name='Parameter_value' 
WITH RECOMPILE

4,語句級別的重新編譯

在SP中,使用查詢選項 option(recompile),只重新編譯該語句級別的執行計劃

select column_name_list
from dbo.tablename
option(recompile)

SQL Server在執行查詢之後,查詢提示(RECOMPILE)指示儲存引擎將計劃快取拋棄,在下次執行儲存過程時,強制查詢優化器重新編譯,生成新的執行計劃。在重新編譯時,SQL Server 優化器使用當前的變數值生成新的計劃快取。

五,控制執行計劃

優化器會根據查詢選擇執行計劃,選擇索引,表關聯演算法等,但是,當發現優化器選擇了低效的執行計劃時,可以使用hint來控制執行計劃,SQL Server提供了三種類型的hint:

  • 查詢提示(query hint):告知優化器在整個查詢過程中都應用某個提示,
  • 關聯提示(join hint):告知優化器在關聯時使用特定的關聯演算法
  • 表提示(table hint):告知優化器使用表掃描,還是表上特定的索引

1,查詢提示

使用option來設定查詢提示,

  • 用於group by 聚合,可以控制分組的演算法:hash group 和order group
  • 用於控制關聯的演算法, option(hash join)
  • 通常情況下,優化器決定表關聯的順序,可以使用force order選項,使優化器按照join的順序來關聯, option(force order)
  • 使用maxdop來確定語句執行的最大併發度,option(maxdop 1),取消併發執行。
  • 按照指定的引數來優化 option(optimize for (@para_name= constant_value))

2,關聯提示

在 join關鍵字前面使用Loop,Merge和Hash來控制關聯的演算法

3,表提示

在引用的表名後面,通過with()來設定表提示 table_name with(hints),

當使用索引時,使用 with(index(index_name))來設定,

 

參考文件: