很多時候,當我執行查詢調優的時候,引發查詢性能糟糕的問題一般都是與參數化相關的。 一方面,參數化是查詢處理器核心的基本主題。它能顯著影響查詢性能。另一方面,大家很少對這一主題進行詳盡的瞭解。 因此我準備寫一個系列的隨筆來介紹關於參數化的問題。第一篇我將介紹關於計劃緩存的內容。為了理解參數化,有必要先 ...
很多時候,當我執行查詢調優的時候,引發查詢性能糟糕的問題一般都是與參數化相關的。
一方面,參數化是查詢處理器核心的基本主題。它能顯著影響查詢性能。另一方面,大家很少對這一主題進行詳盡的瞭解。
因此我準備寫一個系列的隨筆來介紹關於參數化的問題。第一篇我將介紹關於計劃緩存的內容。為了理解參數化,有必要先理解理解執行計劃如何被緩存。
SQLServer保留一定數量的記憶體來保存執行計劃緩存。這就是執行計劃(和一下其他結構)被緩存為了未來重用的地方。查詢(或語句)和批處理之間的區別時會引發混淆。前者是作為一個原子一次執行一個查詢的單一命令。後者是一個被解析、簡化、優化、編譯並最終被執行的單位,包含多個語句。這個單位為優化器生成一個執行計劃,因此執行計劃緩存存儲執行計劃,每一個代表一個批處理。
使用sys.dm_exec_cached_plansDMV可以查看執行計劃緩存的內容。如果你打算看批處理文檔和計劃XML,那麼可以使用下麵的查詢:
SELECT BatchText = BatchTexts.text , QueryPlan = BatchPlans.query_plan , ExecutionCount = CachedPlans.usecounts , ObjectType = CachedPlans.objtype , Size_KB = CachedPlans.size_in_bytes / 1024 FROM sys.dm_exec_cached_plans AS CachedPlans CROSS APPLY sys.dm_exec_query_plan (plan_handle) AS BatchPlans CROSS APPLY sys.dm_exec_sql_text (plan_handle) AS BatchTexts;
當查詢處理器遇到一個批處理時,首先檢查是否在緩存中已經有能被重用的計劃。這是因為分析和編譯批處理的成本是相當昂貴的。如果已經有了這個精確的執行計劃,那麼能節省大量的資源和時間。查詢處理器如何查詢批處理是否在緩存中的那?當一個新的批處理產生,它的哈希值被計算並且與已經在緩存中的執行計劃比較。假如匹配的到,批處理文檔按順序去驗證這的確是相同的批處理(這是因為多重文檔值可能結果是相同的哈希值)。
一些其他元素也需要被比較,例如ANSI_NULLS 和ARITHABORT等選項。有幾個類似的設置選項會影響當前會話中的查詢如何被執行。兩個會話執行完全相同的批處理,使用不同的設置選項可能會產生不同的結果並且這就是為什麼必須去通過不同的油畫過程和產生不同的執行計劃。因此當查詢處理器發現一個計劃在緩存中,它需要比較這7個設置選項是否相同。
如果沒有匹配上,則需要經過解析、簡化、油畫、和編譯計劃等過程。新產生的計劃將被放到記憶體中為將來使用(多數情況)。
一旦查詢處理器發現緩存中有一個執行計劃,它仍然會驗證執行計劃是否仍然可用。例如,潛在的表和索引的架構已經在計劃生成後發生了變化,或許新的列被加入表中,或者索引被刪除…;另外一個原因統計信息過期。如果計劃基於統計信息生成的,就會被標記過期(表的大量變動)。這些都會導致新的執行計劃無效。
如果計劃是有效的,查詢處理器最終能執行它。整個過程看起來很長,但是實際上是非常快。如果計劃無效,那麼就會觸發重現編譯事件。這意味著再次進行批處理優化,然後新的執行計劃被生成、放置在原來無效的緩存記憶體中。重編譯已經存在的計劃比編譯新的要快。因為它沒必有解析和簡化步驟。
這裡有一個圖來總結這一過程
一般來說,你的目標是提高計劃重用率。越是重用的多意味在編譯相同執行計劃時越少的資源被浪費,批處理更高效、性能更好。
現在請看下麵這個類似的執行查詢應用:
SELECT OrderId , OrderDate , OrderAmount , OrderStatus FROM Sales.Orders WHERE CustomerId = 73922;
如果查詢一秒內不執行50次,每次有不同顧客ID,那麼這個計劃緩存將很快爆炸。每個查詢用不同的用戶將被當做新的批處理(因為查詢的哈希值在緩存中找不到),並且將必須經歷整個解析--優化的處理過程。除此之外,每一個計劃一定要放到記憶體中,因此大量記憶體分配活動在幕後進行。既然記憶體有限,有大量的計劃存儲。計劃緩存將增加大量數據緩存,因此更少的數據也存儲在緩存中,並且記憶體管理器將必須移除舊的計劃緩存以便去有更多的空間為新的計劃。
這就是參數化扮演重要的角色。下一章將介紹執行查詢的七種方式。