SQL Server數據庫系統的IO性能受到物理硬盤的IO延遲和SQL Server請求執行的IO操作的影響。在監控硬盤性能時,最主要的度量值(metric)是IO延遲,IO延遲是指從應用程序創建IO請求,到硬盤完成IO請求的時間延遲。如果物理硬盤不能及時完成IO請求,跟不上請求負載的速度,那么SQL Server就容易出現性能問題。SQL Server內部在執行一些特定的操作時,會和硬盤做讀寫交互,這也會影響物理硬盤響應SQL Server的IO請求的性能,使查詢進程處於PageIOLatch或WriteLog等待。
一,使用性能計數器(Performance counter)監控硬盤 IO
首先要了解操作系統的存儲管理,硬盤在操作系統分為:物理硬盤(Physical Disk)和邏輯硬盤(Logical Disk)。Windows可以在一個Physical Disk上划出若干個邏輯分區,每一個邏輯分區是一個Logical Disk。對於分配在同一個Physical Disk上的Logical Disks,其讀寫操作共享Physical Disk的IO帶寬。Windows給每一個Logical Disk分配一個盤符,App通過盤符來讀寫數據。
對應地,硬盤的性能有兩組計數器:Logical Disk 和 Physical Disk,其中邏輯硬盤是物理硬盤的邏輯分區:
- Logical Disk 計數器按照邏輯分區記錄每個邏輯分區的讀寫IO信息,由於App通過盤符來讀寫數據,通過logical Disk 計數器可以了解不同App向不同盤符發出的讀寫請求有多少。
- Physical Disk 計數器是按照物理磁盤,記錄每一個物理磁盤的讀寫IO,如果該物理硬盤上有多個邏輯分區,那么把所有邏輯分區的IO加和到一起,統計物理硬盤的IO性能,監控硬盤的響應速度,能夠真正了解硬件的實際IO量。推薦監控某一塊Physical Disk,而不要粗暴地監控所有的物理硬盤,多數情況下,一塊Physical Disk的IO很忙,而其他Physical Disk很空閑,原因是數據庫文件分布的邏輯硬盤是同一塊物理硬盤,導致單塊物理硬盤需要處理的IO請求過多,為了避免這種情況的發生,需要把數據庫文件均勻分布在不同的物理硬盤上。
那么,Windows性能監控器都有哪些硬盤的性能計數器了?
1,Disk Queue Length
硬盤隊列長度是等待被Physical Disk處理的IO請求的數目。如果一個App發出一條讀請求,但是目標Disk正在處理其他IO Task,那么這個新的請求就會被放在Disk queue中,Disk queue Length就是1,硬盤的請求隊列的長度,能夠衡量硬盤的工作負載,隊列長度越長,說明硬盤接收到的IO請求越多,完成一次IO請求需要的處理時間就越長,從一定程度上表明,硬盤性能不能滿足業務的需求了。
- Avg. Disk Queue Length
- Avg.Disk Read Queue Length
- Avg.Disk Wirte Queue Length
- Current Disk Queue length
2,傳輸(Transfer)時間
Transfer是Disk 的一次完整的I/O動作,表示從尋道,讀寫數據,到傳輸完成。在統計時,Transfer 是 Read 和 Write的加和。
- Avg. Disk sec/Transfer : 磁盤每一次讀寫所用的平均時間。
- Disk Transfers/sec : 磁盤每秒處理的讀寫次數。
- Avg.Disk Bytes/Transfer:Disk 每次IO傳送的Bytes數
3,讀寫時間百分比
硬盤的工作時間(elapsed time)是指硬盤用於執行read/write操作的時間
- % Disk Time:硬盤的工作時間( elapsed time)和處理IO請求的總時間的比值。
- % Disk Read Time
- % Disk Write Time
- % Idle Time
4,IO拆分
一次IO拆分成多次IO來實現,IO拆分的原因是文件出現碎片,一次IO請求讀取的非連續的數據段,那么硬盤子系統會把該請求分成多次執行,測量IO拆分的比例能夠反映文件存儲的分散程度。
還有一個原因會導致IO拆分,這就是一次讀取的數據過大,導致無法通過一次IO請求返回,這就需要把IO請求拆分成多次。
Split IO/Sec reports the rate at which I/Os to the disk were split into multiple I/Os. A split I/O may result from requesting data of a size that is too large to fit into a single I/O or that the disk is fragmented.
二,在系統級別監控物理Disk的IO性能
使用性能監控器來偵測IO性能,用於監控IO性能的計數器主要是物理硬盤的讀寫:
- Physical Disk\Disk Reads/sec
- Physical Disk\Disk Writes/sec
這兩個計數器的性能指標:
- <10 ms 沒有性能問題
- 10~20ms 存在問題
- 20~50ms 性能較低
- >50ms 存在嚴重的性能問題
1,監控物理Disk的IO延遲
在Windows級別上對Physical Disk的IO延遲進行分析,主要依賴於Performance Monitor的計數器,衡量物理Disk的IO延遲的計數器主要有三個:
- Avg. Disk sec/Transfer:Disk每一次讀寫操作所用的平均時間
- Avg. Disk sec/Read:Disk每一次讀操作所用的平均時間
- Avg. Disk sec/Write:Disk每一次寫操作所用的平均時間
avg.Disk sec/(Transfer,Read,Write),能夠很好的反映Disk的IO速度,推薦的衡量Disk的IO速度的基線(baseline):
- 很快:<10ms
- 一般:10-20ms
- 有點慢:20-50ms
- 非常慢:>50ms
2,分析Data Collector收集的計數器數值
下圖是產品環境中一台Server的計數器數值圖表,將IO延遲的度量值按比例放大1000倍,這樣圖表顯示的單位就是ms。
- %Idle Time:在60%左右浮動,說明Disk不是很忙碌
- Avg.Disk sec/Write:大多數情況下都是10ms以下,偶爾波動,說明Disk的寫延遲比較低
- Avg.Disk sec/Read:讀延遲大多數情況下都是在40ms以上,鮮有低於40ms,偶爾達到峰值,說明Disk的讀延遲非常高
- Avg.Disk sec/Transfer:讀寫延遲的均值在30ms左右,時有波動,在%Idle Time曲線不波動時,Disk的讀寫延遲也有波動,說明Disk的讀寫延遲不穩定
初步判斷,Disk的讀寫延遲非常高,Disk的IO性能較差,IO速度慢

3,監控物理Disk的IO次數
根據Disk的IO次數來界定Disk性能,沒有統一的閾值,一般通過監控計數值來獲取一個趨勢,設置一個基線,如果在Disk比較忙碌時,遇到異常的谷值,那么就需要查看是否出現參數嗅探問題和Disk IO密集的查詢,異常的谷值一般是由查詢語句請求的數據量太多造成的,需要對查詢語句進行性能調優。
系統級經常用到的Disk性能計數器是PhysicalDisk計數器:
- Avg. Disk Queue Length :提供Disk阻塞程度的主要度量值,表示在 sample interval期間,Disk等待處理的IO請求隊列的平均長度,即等待被Disk處理的IO請求的數量
- % Idle Time:Disk的空閑程度,可以反推出Disk的忙碌程度
- Disk (Reads/Writes/Transfers)/sec:每秒Disk執行讀寫操作數量
隊列長度波動很大,在%Idle Time 升高時,IO數量降低,沒有發現明顯的異常谷值。

4,監控物理Disk讀寫的數據量
這幾個計數值,對監控物理Disk的讀寫性能,意義不大,僅僅作為參考。
- Avg.Disk Bytes/(Read,Write,Transfer)表示:在物理Disk執行讀寫操作時,物理Disk從Disk讀取到內存的字節數量,從內存寫入到Disk的字節數量,以及兩者的總字節數量
- Disk Bytes/sec:在物理Disk執行讀寫操作時,數據從Disk傳輸到內存,或從內存寫入到Disk的字節速度,好的Disk,其值在20-40MB之間,一般Disk,其值在20MB以下

三,SQL Server內部操作對Disk IO性能的影響
SQL Server能夠緩存從Disk加載的數據頁,正常情況下,大部分操作不需要任何物理讀操作,不需要Disk的物理IO參與就能完成,但是,有一些操作,必須和物理Disk進行IO操作,才能完成。SQL Server和物理Disk進行IO交互的操作:
- 對於內存中沒有緩存的數據,第一次訪問時,需要將數據從數據文件讀取到內存中,SQL Server訪問的任何數據必須緩存到內存中,如果不在內存中,SQL Server發送讀請求,將數據頁從物理Disk讀取到內存中,這個過程叫做物理讀;如果數據存在於內存中,SQL Server直接訪問,這個過程叫做邏輯讀。
- 在任何修改操作提交之前,預寫事務日志記錄到日志文件,在CheckPoint和LazyWriter運行時,數據被寫入數據文件。
- 執行CheckPoint時,將緩存中的臟頁寫入數據文件,臟頁是指載入內存之后被修改過的數據頁,內存中的數據和數據文件中的數據不一致,由CheckPoint觸發的物理寫操作和內壓沒有關系,和用戶修改的數據量有關,用於控制還原的時間間隔。
- 當Buffer Pool空間不足,Free Buffer List減少到臨界值時,LazyWriter進程主動將內存中的一些很久沒有訪問過數據頁面和執行計划清空,如果數據頁面是臟頁,那么將其寫入到數據文件,LazyWriter和內存壓力有關,由於內存可用的Free Buffer不足導致LazyWriter進程執行清理操作。
- IO密集型操作,比如檢查數據庫的一致性(DBCC CheckDB),重建索引,更新統計信息,數據庫備份等,會帶來大量的Disk IO操作
SQL Server只會讀取數據文件,只要數據緩存在內存中,理想情況下,SQL Server不會執行任何物理讀操作,也不需要從物理Disk加載數據到內存,SQL Server執行讀取操作性能和內存的緩存能力有直接關系,也和用戶讀取的數據量有關。
SQL Server的寫操作分為寫數據文件和寫日志文件。寫入日志文件的數據量,完全由數據修改量決定,和內存壓力沒有關系;寫入數據文件的數量,主要和修改量有關。LazyWriter和內存壓力有關系,一旦內存有壓力,LazyWriter自動啟動,負責清理最久未被訪問的緩存,釋放內存,增加可用的Free buffer數量。
因此,SQL Server請求的物理Disk的讀操作數量和內存有直接關系,內存越充足,緩存的數據量越多,物理Disk的讀操作的數量就會越少,邏輯讀的數量不會減少;SQL Server請求的物理Disk的寫操作數量和用戶執行的數據修改量有直接關系,和內存是否存在壓力關系很微小。在執行物理disk的讀寫請求時,SQL Server的查詢進程產生PageIOLatch等待,表示進程正在執行物理讀操作,該等待可以從DMV:sys.dm_exec_requests 查看到:
select r.session_id, r.blocking_session_id as blocking, r.wait_type as Current_Wait_Type, r.wait_resource, r.last_wait_type, r.wait_time, r.status, r.command, r.cpu_time,r.reads,r.writes,r.logical_reads, r.total_elapsed_time, r.start_time, db_name(r.database_id) as database_name, SUBSTRING( st.text, r.statement_start_offset/2+1, ( CASE WHEN r.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), st.text)) ELSE (r.statement_end_offset - r.statement_start_offset)/2 END ) ) as IndividualQueryStatement from sys.dm_exec_requests r outer APPLY sys.dm_exec_sql_text(r.sql_handle) as st where (r.wait_type<>'MISCELLANEOUS' or r.wait_type is null) and r.session_id>50 and r.session_id<>@@spid

PageIOLatch 等待:表示進程正在從物理Disk加載數據到內存,即進程在進行物理讀操作,從Reads字段能夠看到物理讀的數量
WriteLog 等待:表示事務正在修改數據,SQL Server將預先將事務日志記錄寫入到事務日志文件
參考文檔:
Memory - Lazy Writer and Checkpoint
SQL Server disk performance metrics – Part 1 – the most important disk performance metrics
Measuring Disk Latency with Windows Performance Monitor (Perfmon)
