查詢優化器基於當前的統計信息和參數,衡量開銷以後,選擇「最優」的執行計劃,須要注意的是,「最優」是相對的,優化器不可能窮舉全部的執行計劃來評估其開銷,這個「最優」的標準是對當前參數和當前的統計信息來講的,優化器從生成的備選執行計劃中選擇開銷最小的。因爲執行計劃的編譯和生成是很耗費資源和時間的,所以,SQL Server會把生成的任一執行計劃緩存起來,以便重用。算法
因爲關係表的數據和結構可能發生改變,數據更新會致使統計信息過期,而以前的參數可能不具備表明性,使得已生成的執行計劃不能表明其餘參數值,致使查詢性能低下。所以,應當監控執行計劃的性能,當發現參數嗅探問題時,應該及時修改代碼以重編譯;當發現統計信息過時時,應及時更新統計信息等。sql
SQL Server使用特定的緩存機制,以重用第一次執行查詢時生成的執行計劃,總的來講,SQL Server內部有如下四種執行計劃緩存機制:數據庫
對於Adhoc查詢的緩存,是SQL Server自動進行的,用戶不能干預,然後兩種是用戶能夠干預的,用戶能夠經過優化代碼來複用「模板化」的查詢。所謂模板化語句,是指除了個別的常量發生變化以外,語句主體不變,能夠把變化的常量做爲一個參數,不變的語句主體做爲一個模板來處理,SQL Server優化器把這個模板編譯成執行計劃,傳入不一樣的參數會使用相同的執行計劃。緩存
1,Ad Hoc查詢緩存性能優化
對於任意一個Ad Hoc查詢,SQL Server都會緩存它的執行計劃,可是,只有當批處理語句的文本徹底匹配時,纔會複用已緩存的執行計劃,徹底匹配的處理過程是:併發
大量的Ad Hoc查詢緩存會佔用計劃緩存的空間,這些緩存可能只會被使用一次,之後不再會被使用。若是數據庫系統中存在大量的一次性查詢語句,應設置Server 級別的性能優化選項:Optimize for Ad hoc Wrokloads。oop
「針對即席工做負載進行優化」是一個Server級別的性能優化選項,用於提升包含許多臨時批處理的工做負載的計劃緩存的效率,若是把該選項設置爲True,則數據庫引擎在首次編譯批處理時只保留計劃緩存中的一個存根,而不是存儲整個執行計劃。當再次調用該批處理時,數據庫引擎識別出該批處理在以前被執行過,進而從計劃緩存中刪除該執行計劃的存根,並把徹底編譯的執行計劃添加到計劃緩存中。當非參數化的Ad-Hoc查詢較多時,能夠避免計劃緩存存儲過多的不會被複用的執行計劃。性能
2,參數化Ad-Hoc優化
SQL Server 自主決定是否把查詢中的常量做爲參數來對待,除了常量不一樣以外,其餘語句主體都相同,這就是這個查詢語句的模板,不一樣的參數使用相同的執行計劃。spa
例如,對於如下兩個查詢語句,除了常量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 ID=@id
3,Prepared 查詢緩存
用戶使用sys.sp_executesql 控制參數和模板,只要模板相同,而參數不一樣,均可以複用已緩存的執行計劃。
4,存儲過程
用戶建立的存儲過程,在第一次執行時,編譯和生成執行計劃,並緩存到計劃緩存中,當下次調用相同的存儲過程,即便使傳遞的參數不一樣,SQL Server都會複用執行計劃。
參數嗅探是指在建立存儲過程,或者參數化查詢的執行計劃時,根據傳入的參數進行預估並生成執行計劃。SQL Server生成的執行計劃對當前參數來講是最優的,而對其餘大多數參數來講,是很是低效的。有些時候,針對一個查詢的第一次傳參,已經產生了一個執行計劃,當後續傳參時,因爲存在對應參數的數據分佈等問題,致使原有的執行計劃沒法高效地響應查詢請求,這就出現參數嗅探問題。
參數嗅探的本質是優化器根據參數來生成的執行計劃不是最優的,致使優化器在複用執行計劃時,語句的查詢性能變得十分低下。對於參數嗅探問題,必須從新生成執行計劃,可使用語句重編譯,編譯提示(optimize for)等功能來避免。
SQL Server不會永久保存計劃的緩存,而且存在緩存中的執行計劃也不會永久不變,每一個計劃都會有一個Age值,當SQL Server探測到內存壓力時,會觸發Lazy Writer進程,用於清空全部的髒頁,釋放數據緩存。當掃面到計劃緩存時,會下降Age值,當複用一次計劃時,會增長Age值。當系統遇到內存壓力,或Age值降到0時,執行計劃會被移除內存。
除了這兩個條件以外,當遇到下面的條件時,執行計劃一會被移除內存,被從新編譯:
在執行計劃執行過程當中,執行計劃被從新編譯,是優化器根據表結構,索引結構和統計信息作出優化的結構,目的是爲了不繼續使用不合適的執行計劃。
修改存儲過程,觸發器等模塊(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:
1,查詢提示
使用option來設置查詢提示,
2,關聯提示
在 join關鍵字前面使用Loop,Merge和Hash來控制關聯的算法
3,表提示
在引用的表名後面,經過with()來設置表提示 table_name with(hints),
當使用索引時,使用 with(index(index_name))來設置,
參考文檔: