微軟工程師的一個工程師曾經對性能調優有一個很是形象的比喻:剝洋蔥 。我也很是承認,讓咱們來一層一層撥開外面它神祕的面紗。sql
下面祭出的是咱們在給客戶分析數據庫性能問題最經常使用的圖。數據庫
看完這個圖,你是否是對性能調優有了個基本的概念了.一般來說咱們會依照下面的順序來進行分析:緩存
硬件能力安全
系統規模性能優化
數據庫內部因素架構
軟件環境併發
這4個的順序能夠有所調整或者交換,可是對於系統的性能優化必定要從全局出發。切勿一來就深刻到某一個SQL語句的優化,由於可能你花費大量的app
時間吧一個SQL從20s 優化到1s,可是整個系統的卡慢仍然存在。負載均衡
最後纔是性能
業務模型及架構
代碼設計
不廢話了,開整開整,直接上乾貨。
時間:2018年1月某天
事件:某醫院客戶 下午4點 忽然出現大面積的卡慢。整個系統出現嚴重問題,信息中心電話打爆,醫院工程師手足無措。
萬幸的是咱們給數據庫裝了‘攝像頭’,下面就從監控錄像來看看發送了什麼。而後加以解決
在問題發生時間段內CPU使用率在20%如下,正常。
從下面的圖像顯示,內存使用正常。
頁生命週期
可用內存
IO隊列平均值很低,15.48 左右有個瞬時的高點,可留意這段時間有沒有批量的寫入。
總的來看,硬件資源是足夠的。
問題發生時,每秒的批請求書並非一個上升趨勢,反而有所降低。這是由於系統的擁堵,等待 ,影響了系統的吞吐量。
從會話和慢語句的趨勢圖能夠看到,問題發生的時間和客戶描述徹底吻合,咱們能夠判定自己事故的確是慢在數據庫。
檢查者個時間段運行中的語句,能夠發現下午15.58左右,數據庫中開始出現愈來愈多的CMEMTHREAD等待。
一直到1900頁16.08分的時候,出現了最高達100個併發同時出現CMEMTHREAD等待
微軟官方的描述:在任務正在等待線程安全的內存對象時發生。 當多個任務嘗試從同一個內存對象分配內存致使爭用時,等待時間可能會增長。
這個描述很晦澀,感受仍是徹底不知道等待類型是怎麼回事,應該怎麼處理這類問題。
實際上,從官方描述來看是內存爭用的問題,可是實際上這個問題的關鍵在於多個任務的爭用,其實是併發的執行的問題。
內存對象有三種類型的(Global,Per Numa Node,Per CPU)。 SQL Server將容許對內存對象進行分段,以便只有同一節點或cpu上的線程具備相同的底層CMemObj,從而減小來自其餘節點或cpu的線程交互,從而提升性能和可伸縮性。減小內存的併發爭用
SELECT type, pages_in_bytes, CASE WHEN (0x20 = creation_options & 0x20) THEN 'Global PMO. Cannot be partitioned by CPU/NUMA Node. TF 8048 not applicable.' WHEN (0x40 = creation_options & 0x40) THEN 'Partitioned by CPU.TF 8048 not applicable.' WHEN (0x80 = creation_options & 0x80) THEN 'Partitioned by Node. Use TF 8048 to further partition by CPU' ELSE 'UNKNOWN' END from sys.dm_os_memory_objects order by pages_in_bytes desc
若是你發現,Partitioned by Node 的內存開銷是排在前面的,可使用TRACE FLAG 8048來減小CMEMTHREAD等待.
從圖中能夠看到,客戶的 Partitioned by Node 是比較靠後的,排在14位。
3. 補丁
這類場景是最多見的。若是在系統中發現出現大量的CMEMTHREAD等待,優先考慮數據庫是否是已經安裝最新的補丁
2012 ,2014 當您執行許多特殊查詢在 SQL Server 2012年或 SQL Server 2014 CMEMTHREAD 等待
目前數據庫的版本是 11.0.5556.0 而前面提到的補丁,安裝後的版本是:11.0.5623.0
都是相似下面的語句,最高時,併發超過100.
SELECT * INTO #Tmp from TB where 1=2
特色以下:
1.語句簡單 開銷都小於5不會產生並行
2.都採用了select into #temptable的形式
就像上面分析的同樣,CMEMTHREAD等待是一個併發問題,而不是一個內存問題。在其餘方案行不通的時候,咱們能夠經過調整此類語句的寫法,減小CMEMTHREAD等待.
目前系統是單機運行的狀態,這實際上是不多見的。存在少許OLAP 和OLTP業務混合的狀況。後續咱們會給客戶規劃 讀寫分離 或者負載均衡的解決方案。在
至少須要安裝前面發的解決等待問題的FIX。建議是直接安裝到目前爲止最新的2012 SP4補丁。
optimize for ad hoc workloads 從0修改成1 。針對將即席執行計劃ad hoc plans 插入到計劃緩存中的時候 場景,減小ad hoc 查詢佔用的內存。
select * into #temptable 會產生大量的閂鎖爭用,防止在CMEMTHREAD 等待消除後,出現大量的pagelatch 閂鎖爭用。我經歷過不少案例,解決了前面的一個擁堵以後,
後面有產生了新的等待,致使性能更差了。請記住,優化是一個長期的,按部就班的過程。
目前部分tempdb文件放在S,通常分放在D盤。建議都遷移到S盤(存儲上面),增長tempdb的響應速度。若是可能的話,使用SSD來最大化tempdb的性能,將會是不錯的選擇。
修改代碼一般都是放在最後面的,由於要牽涉的狀況比較多。前面的手段80%的狀況下,均可以解決問題。剩下的20%,咱們須要,檢查程序中的邏輯,看看這些的語句都是什麼業務產生的。什麼條件會觸發這類業務.對應下面相似的語句都使用存儲過程,或者參數化後的方式,減小編譯和重編譯的次數。另外此類語句都會併發建立臨時表,可能經過調整tempdb的設置,加快此類語句的執行速度,減小同一時間此類語句的併發數量。
通過前面的幾個優化手段,次日開始,沒有再出現過一次CMEMTHREAD的等待。
經過這篇文件你應該已經徹底學會了數據庫性能調優的思想。他告訴了咱們出現問題時,怎麼動手一步一步的排查問題,就像剝洋蔥同樣一層一層的剝開。
微軟官方博客對這類等待的原理和如何調試How It Works: CMemThread and Debugging Them
SQL Server 2016 對這裏問題進行了進一步的優化,詳細參考 SQL 2016 – It Just Runs Faster: Dynamic Memory Object (CMemThread) Partitioning