一文教會你數據庫性能調優(附某大型醫院真實案例)

前言

 微軟工程師的一個工程師曾經對性能調優有一個很是形象的比喻:剝洋蔥 。我也很是承認,讓咱們來一層一層撥開外面它神祕的面紗。sql

 

 

六大因素

下面祭出的是咱們在給客戶分析數據庫性能問題最經常使用的圖。數據庫

看完這個圖,你是否是對性能調優有了個基本的概念了.一般來說咱們會依照下面的順序來進行分析:緩存

硬件能力安全

系統規模性能優化

數據庫內部因素架構

軟件環境併發

這4個的順序能夠有所調整或者交換,可是對於系統的性能優化必定要從全局出發切勿一來就深刻到某一個SQL語句的優化,由於可能你花費大量的app

時間吧一個SQL從20s 優化到1s,可是整個系統的卡慢仍然存在。負載均衡

最後纔是性能

業務模型及架構

代碼設計

 

實戰案例

 

不廢話了,開整開整,直接上乾貨。

時間:2018年1月某天

事件:某醫院客戶 下午4點 忽然出現大面積的卡慢。整個系統出現嚴重問題,信息中心電話打爆,醫院工程師手足無措。

萬幸的是咱們給數據庫裝了‘攝像頭’,下面就從監控錄像來看看發送了什麼。而後加以解決

 

硬件能力

CPU

在問題發生時間段內CPU使用率在20%如下,正常。

Memory

從下面的圖像顯示,內存使用正常。

頁生命週期

 

 可用內存

 

 

IO

 IO隊列平均值很低,15.48 左右有個瞬時的高點,可留意這段時間有沒有批量的寫入。

總的來看,硬件資源是足夠的。

系統規模

問題發生時,每秒的批請求書並非一個上升趨勢,反而有所降低。這是由於系統的擁堵,等待 ,影響了系統的吞吐量。

 數據庫內部因素

等待

慢語句

從會話和慢語句的趨勢圖能夠看到,問題發生的時間和客戶描述徹底吻合,咱們能夠判定自己事故的確是慢在數據庫。

什麼致使的慢

檢查者個時間段運行中的語句,能夠發現下午15.58左右,數據庫中開始出現愈來愈多的CMEMTHREAD等待。

 

 

一直到1900頁16.08分的時候,出現了最高達100個併發同時出現CMEMTHREAD等待

什麼是CMEMTHREAD等待

微軟官方的描述:在任務正在等待線程安全的內存對象時發生。 當多個任務嘗試從同一個內存對象分配內存致使爭用時,等待時間可能會增長。

這個描述很晦澀,感受仍是徹底不知道等待類型是怎麼回事,應該怎麼處理這類問題。

 

實際上,從官方描述來看是內存爭用的問題,可是實際上這個問題的關鍵在於多個任務的爭用,其實是併發的執行的問題。

場景

  1. 出如今數據庫編譯或重編譯時,將即席執行計劃ad hoc plans 插入到計劃緩存中的時候
  2.  NUMA架構下,內存對象是按照節點來分區的

內存對象有三種類型的(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等待,優先考慮數據庫是否是已經安裝最新的補丁

 

2008 r2: FIX: SQL Server 2008 R2 performs poorly when most threads wait for the CMEMTHREAD wait type if the threads use table variables or temp tables to load or update rowsets

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 查詢佔用的內存。

增長TEMPDB數據文件的個數

select * into #temptable 會產生大量的閂鎖爭用,防止在CMEMTHREAD 等待消除後,出現大量的pagelatch 閂鎖爭用。我經歷過不少案例,解決了前面的一個擁堵以後,

後面有產生了新的等待,致使性能更差了。請記住優化是一個長期的,按部就班的過程。

遷移TEMPDB數據文件的位置

目前部分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

相關文章
相關標籤/搜索