Sql-Server

為什麼我的查詢突然比昨天慢?

  • October 6, 2019

$$ Salutations $$ (勾選一項)

[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,

我有一個**(勾選所有適用項)**

[ ] query [ ] stored procedure [ ] database thing maybe  

執行良好**(如果適用)**

[ ] yesterday [ ] in recent memory [ ] at some point 

但現在突然變慢了。

我已經檢查以確保它沒有被阻止,並且它不是一些長期執行的維護任務、報告或其他帶外程序的受害者。

有什麼問題,我應該怎麼做,我可以提供什麼資訊來獲得幫助?

[*Insert appropriate closing remarks*]

親愛的

$$ your name here $$! 哦不,我很遺憾聽到這個消息!讓我們從一些基礎知識開始,讓您快速搞定。

您遇到的事情稱為參數嗅探

這是一個奇怪的奇怪問題的出路。這個名字從舌頭上滾下來。就像德語中的松鼠一樣。

它通常是你的朋友。

當查詢到達您的伺服器時,必須編譯計劃。為了以後節省時間和資源,執行計劃會根據估計的行進行記憶體,該參數將導致您的程式碼處理和返回。

描述這種情況的最簡單方法是想像一個需要從兩個不平衡的群體中計算事物的儲存過程。

例如:

  • 未受傷的穿著 CrossFit 襯衫的人:零
  • 穿著 CrossFit 襯衫的人在畏縮時畏縮:所有

顯然,該程式碼的一次執行將比另一次執行更多的工作,並且您想要執行完全不同數量的工作的查詢計劃看起來完全不同。

我反對什麼?

這是一個真正難以發現、測試和修復的問題。

  • 很難找到,因為它不會始終如一地發生
  • 很難測試,因為您需要知道哪些參數會導致不同的計劃
  • 這很難修復,因為有時它需要查詢和索引調整
  • 這很難修復,因為您可能無法更改查詢或索引
  • 這很難修復,因為即使您更改查詢或索引,它仍然可能會回來

快速修復

有時,您所需要的只是一點清晰。或者更確切地說,您的計劃記憶體確實如此。

如果是儲存過程

嘗試執行EXEC sys.sp_recompile @objname = N'schema.procname'。這將導致該過程在下次執行時重新編譯一個新計劃。

這不能解決的問題:

  • 目前執行它的程序。

這不能保證:

  • 重新編譯後執行的下一個程序將使用一個參數,該參數可以為您提供一個好的計劃。

您也可以指向sp_recompile一個表或視圖,但請注意所有觸及該表或視圖的程式碼都將重新編譯。這可能會使問題變得更加困難。

如果是參數化查詢

你的工作有點困難。您需要跟踪 SQL 句柄。你不想釋放整個計劃記憶體——就像sp_recompile對錶或視圖使用一樣,你可能會觸發(哈哈哈)一大堆意想不到的後果。

找出該命令的最簡單方法是執行sp_BlitzWho *! 有一個名為“修復參數嗅探”的列,其中包含從記憶體中刪除單個計劃的命令。但是,這與重新編譯具有相同的缺點。

這不能解決的問題:

  • 目前執行它的程序。

這不能保證:

  • 重新編譯後執行的下一個程序將使用一個參數,該參數可以為您提供一個好的計劃。

我還需要幫助!

我們將需要以下東西:

  • 好的查詢計劃,如果可能的話
  • 糟糕的查詢計劃
  • 使用的參數
  • 有問題的查詢
  • 表和索引定義

獲取查詢計劃和查詢

如果查詢正在執行,您可以使用sp_BlitzWho * 或sp_WhoIsActive來擷取目前正在執行的查詢。

EXEC sp_BlitzWho;

EXEC sp_WhoIsActive @get_plans = 1;

堅果

如果查詢目前沒有執行,您可以使用sp_BlitzCache * 在計劃記憶體中檢查它。

如果您使用的是 SQL Server 2016+,並且打開了查詢儲存,則可以使用sp_BlitzQueryStore *。

EXEC dbo.sp_BlitzCache @StoredProcName = 'Your Mom';

EXEC dbo.sp_BlitzQueryStore @StoredProcName = 'Your Mom';

這些將幫助您跟踪儲存過程的記憶體版本。如果只是參數化程式碼,您的搜尋會有點困難。不過,這可能會有所幫助:

EXEC dbo.sp_BlitzCache @QueryFilter = 'statement';

您應該從其中任何一個中看到相當相似的輸出。同樣,邀請酷藍色點擊列的查詢計劃是您的朋友。

堅果

共享計劃的最簡單方法是使用Paste The Plan *,或將 XML 轉儲到 pastebin。要做到這一點,請點擊其中任何一個吸引人的藍色點擊列。您的查詢計劃應出現在新的 SSMS 選項卡中。

堅果

如果您對共享公司的程式碼和查詢很敏感,您可以使用Sentry One 的免費計劃資源管理器工具來匿名化您的計劃。請記住,這使得獲得幫助變得更加困難——匿名程式碼更難閱讀和理解。

我們討論的所有這些工具都應該返回查詢文本。你不需要在這裡做任何其他事情。

獲取參數有點困難。如果您使用的是Plan Explorer,底部有一個選項卡,可以為您列出所有內容。

堅果

如果您使用的是sp_BlitzCache *,則有一個可點擊的列,它為您提供儲存過程的執行語句。

堅果

獲取表和索引定義

您可以輕鬆地右鍵點擊 SSMS 來編寫腳本。

堅果

如果您想一次性獲得所有內容,則 sp_BlitzIndex * 如果您將其直接指向一張桌子會有所幫助。

EXEC dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow2010',
                      @SchemaName = 'dbo',
                      @TableName = 'Users';

這將為您提供表定義(儘管不是作為創建語句),並為所有索引創建語句。

收集這些資訊並將其添加到您的問題中應該可以讓人們獲得足夠的資訊來提供幫助,或者為您指明正確的方向。

我想自己做!

嗯,很酷。我為你感到高興。你這個瘋子。

人們認為他們“修復”參數嗅探的方式有很多:

但是這些實際上只是以不同的方式禁用參數嗅探。這並不是說他們不能解決問題,他們只是沒有真正找到根本原因。

那是因為找到根本原因通常有點困難。您必須尋找那些討厭的“計劃質量問題”。

從快速與慢速計劃開始,尋找不同之處,例如:

  • 使用的索引
  • 加入訂單
  • 串列與並行

還要尋找使您的程式碼對參數嗅探敏感的不同運算符:

  • 查找
  • 排序
  • 加盟類型
  • 記憶體授予(以及擴展,溢出)
  • 線軸

不要太專注於搜尋與掃描、索引碎片或任何人們對貨物的狂熱追求。

通常,有一個非常基本的索引問題。有時程式碼需要稍微重寫。

如果您想了解有關參數嗅探的更多資訊:

如果您正在閱讀本文,並且您認為我錯過了連結或有用的工具,請發表評論。我會盡力保持最新。


引用自:https://dba.stackexchange.com/questions/204565