【等待優化】sql server CXPACKET 等待 導致 CPU飆高、CPU100%


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 等待,大多是並行度問題

 

參考:https://www.cnblogs.com/gered/p/9487793.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM