CXPACKET 已經成為所有等待類型中最常見的一種了。我通常會在多CPU系統的前五位等待類型統計中看見。
【1】CXPACKET 的基本解決策略
聯機叢書:
當嘗試同步查詢處理器交換迭代器時出現。如果針對該等待類型的爭用成為問題時,可以考慮降低並行度。
【1.1】CXPACKET 解釋
當為SQL查詢創建一個並行操作時,會有多個線程去執行這個查詢。每個查詢處理不同的數據集或行集。
因為某些原因,一個或多個線程滯后,而產生了CXPACKET等待狀態。
有一個組織/協調(organizer/coordinator)線程(Thread 0),它需要等待所有線程完成並聚合數據來呈現給客戶端。
組織線程必須等待所有線程完成處理才能進行下一步。由於組織線程等待緩慢的線程完成處理所產生的等待,就叫CXPACKET等待。
請注意,並不是所有的CXPACKET等待類型都是不好的事情。你也許會遇某個CXPACKET等待是完全有意義的案例,有時它也是不可避免的。
如果你在任何查詢上禁止此種等待,那么查詢也許會變慢,因為不能為它執行並行操作。
【1.2】在OLTP上解決CXPACKET的辦法——調整並行度
CXPACKET 這個等待可以簡單理解成CPU相關的等待,主要發生在並行計划中。由於並行計划需要協同多個task同時工作,那么“協同”分配等等操作的時候出現的就是這個等待。
如果 CXPACKET 在你系統中是最為嚴重的等待,這時候一般的表現是你的CPU很高。

解決方案:適當調整並行度

一般建議系統如果超過32個CPU 那么設置成8或者4,如果系統中都是特別短小且頻繁的語句建議設置成1(取消語句並行,要慎重真的符合你的場景才好)
並行開銷的閥值(‘Cost Threshold for Parallelism),主要控制SQL優化器何時選用並行計划,建議默認值,此值設置的越小優化器越容易選擇並行計划。
並行度(Max Degree of Parallelism)的設置是針對實例級別的設置(2016中可以對單獨數據庫設置)
【1.3】Data-warehousing /Reporting server 上的CXPACKET
Data-warehousing /Reporting server: 因為查詢執行時間一般較長,建議設置“Maximum degree of Parallelism”(MAXDOP)為0。
這樣大多數查詢將會利用並行處理,執行時間較長的查詢也會受益於多處理器而提高性能。
【1.4】Mixed System (OLTP& OLAP)
這樣環境會是一個挑戰,必須找到正確的平衡點。我采取了非常簡單的方法。
我設置“Maximum degree of Parallelism”(MAXDOP)為2,這樣意味着查詢仍會使用並行操作但是僅利用2顆CPU。
然而,我把“並行查詢閥值”設置為較高的值,這樣的話,不是所有的查詢都有資格使用並行,除了那些查詢成本較高的查詢。
在一個即有OLTP查詢又有報表服務器的系統上,我發現這樣做運行得很好。
在這里我將會設置“‘Cost Threshold for Parallelism’”為25(如圖)。你可以選擇任何值。但你只能通過在系統上做實驗來找到合適的值。
在下面的腳本中,我設置“Max Degree of Parallelism”為2,這樣的話,那些具有較高成本的查詢(這里是25),將會在2顆CPU上執行並行查詢。
同時,不管服務器有多少顆CPU,查詢只會選擇兩顆CPU來執行。
【2】CPU飆高,但沒有等待,大多因為語句造成的問題
大多是因為SQL語句引起的,比如頻繁短快的表掃描
【2.1】當前進程信息
(1)常見DMV
系統進程:select * from sys.sysprocesses
用戶請求:select * from sys.dm_exec_requests
會話進程:select * from sys.dm_exec_sessions
等待進程:select * from sys.dm_os_wait_stats
(2)詳細語句
--包含批處理中當前運行到的SQL(child_Query) select status,start_time,command,percent_complete,wait_type,text as parent_Query, [child_Query] = SUBSTRING(qt.text,r.statement_start_offset / 2, ( CASE WHEN r.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text))* 2 ELSE r.statement_end_offset END - r.statement_start_offset ) / 2) , session_id,blocking_session_id from sys.dm_exec_requests r cross apply sys.dm_exec_sql_text(r.sql_handle) qt --詳細版,查看CPU消耗最多的10個語句 SELECT TOP 10 [cpu_time], [session_id], [request_id], [start_time] AS '開始時間', [status] AS '狀態', [command] AS '命令', dest.[text] AS 'sql語句', DB_NAME([database_id]) AS '數據庫名', [blocking_session_id] AS '正在阻塞其他會話的會話ID', [wait_type] AS '等待資源類型', [wait_time] AS '等待時間', [wait_resource] AS '等待的資源', [reads] AS '物理讀次數', [writes] AS '寫次數', [logical_reads] AS '邏輯讀次數', [row_count] AS '返回結果行數' FROM sys.[dm_exec_requests] AS der CROSS APPLY sys.[dm_exec_sql_text](der.[sql_handle]) AS dest ORDER BY [cpu_time] DESC
【2.2】查看CPU的調度核數與worker信息
--查看CPU數和user scheduler數目 SELECT cpu_count,scheduler_count FROM sys.dm_os_sys_info --查看最大工作線程數 SELECT max_workers_count FROM sys.dm_os_sys_info
查看機器上的所有schedulers包括user 和system
通過下面語句可以看到worker是否用完,當達到最大線程數的時候就要檢查blocking了
對照下面這個表
各種CPU和SQLSERVER版本組合自動配置的最大工作線程數
CPU數 32位計算機 64位計算機
<=4 256 512
8 288 576
16 352 704
32 480 960
--查看每個CPU schedulers 的使用及任務分配情況 SELECT scheduler_address, scheduler_id, cpu_id, status, current_tasks_count, current_workers_count,active_workers_count FROM sys.dm_os_schedulers
如下圖,核數與查詢信息是對應好的。

【2.3】查看等待信息
如果SQLSERVER存在要等待的資源,那么執行下面語句就會顯示出會話中有多少個worker在等待
結合[sys].[dm_os_wait_stats]視圖,如果當前SQLSERVER里面沒有任何等待資源,那么下面的SQL語句不會顯示任何結果
SELECT TOP 10 [session_id], [request_id], [start_time] AS '開始時間', [status] AS '狀態', [command] AS '命令', dest.[text] AS 'sql語句', DB_NAME([database_id]) AS '數據庫名', [blocking_session_id] AS '正在阻塞其他會話的會話ID', der.[wait_type] AS '等待資源類型', [wait_time] AS '等待時間', [wait_resource] AS '等待的資源', [dows].[waiting_tasks_count] AS '當前正在進行等待的任務數', [reads] AS '物理讀次數', [writes] AS '寫次數', [logical_reads] AS '邏輯讀次數', [row_count] AS '返回結果行數' FROM sys.[dm_exec_requests] AS der INNER JOIN [sys].[dm_os_wait_stats] AS dows ON der.[wait_type]=[dows].[wait_type] CROSS APPLY sys.[dm_exec_sql_text](der.[sql_handle]) AS dest WHERE [session_id]>50 ORDER BY [cpu_time] DESC
【3】總結
(1)從多次歷史經驗來看,如果CPU負載持續很高,但內存和IO都還好的話,這種情況下,首先想到的一定是索引問題,十有八九錯不了。
(2)如果有眾多 CXPACKET 等待,大多是並行度問題
