Trattare con CXPACKET attende - impostazione della soglia di costo per il parallelismo


12

Come seguito alla mia precedente domanda sulla risoluzione dei problemi di perf su un sito Sharepoint , mi chiedevo se potevo fare qualcosa per l'attesa di CXPACKET.

So che la soluzione istintiva è quella di disattivare tutto il parallelismo impostando MAXDOP su 1 - sembra una cattiva idea. Ma un'altra idea è quella di aumentare la soglia di costo prima che inizi il parallelismo. L'impostazione predefinita di 5 per il costo di un piano di esecuzione è piuttosto bassa.

Quindi mi chiedevo se ci fosse già una query già scritta che mi avrebbe trovato le query con il costo del piano di esecuzione più elevato (so che puoi trovare quelle con la massima durata di esecuzione e così via - ma il costo del piano di esecuzione è recuperabile da qualche parte, anche?) e questo mi direbbe anche se una simile query è stata eseguita in parallelo.

Qualcuno ha un tale script a portata di mano o può indicarmi le direzioni DMV, DMF o altre viste del catalogo di sistema pertinenti per scoprirlo?

Risposte:


11

CXPACKETnon è mai una causa; ottiene tutta la colpa, ma è sempre un sintomo di qualcos'altro. È necessario catturare queste domande nell'atto e capire cos'è "qualcos'altro". Potrebbe essere diverso da query a query e la disattivazione del parallelismo è, nella maggior parte dei casi, - come hai suggerito - eccessiva inutilità. Ma è spesso la minima quantità di lavoro, motivo per cui è una "soluzione" così diffusa.

Se è possibile ottenere un piano effettivo per una query che sembra essere responsabile di elevate attese di CXPACKET, caricarlo in SQL Sentry Plan Explorer . Di solito c'è un motivo dietro questo; mostriamo quali operazioni parallele hanno portato all'inclinazione del thread e puoi facilmente correlarlo a stime che sono disattivate (evidenziamo operazioni con stime che sono fuori da almeno una certa soglia). Di solito il problema di fondo è dato da statistiche davvero scadenti / non aggiornate (o non disponibili).

Sfortunatamente ciò che troverai in sys.dm_exec_cached_plans sono piani stimati . Non ti diranno se il piano è diventato parallelo quando è stato effettivamente utilizzato, perché il piano effettivo non è ciò che viene memorizzato nella cache. In alcuni casi ti aspetti di vedere sia un piano seriale che parallelo per la stessa query; non è così che SQL Server gestisce la situazione per piani paralleli che potrebbero essere paralleli in fase di esecuzione. ( Molte informazioni al riguardo qui .)


4

Se si desidera visualizzare il piano di esecuzione effettivo di una query in esecuzione.

SELECT plan_handle FROM sys.dm_exec_requests WHERE session_id = [YourSPID]

Innanzitutto, inserisci il risultato in questa query.

SELECT query_plan FROM sys.dm_exec_query_plan (Enter the result here.)

Ciò mostrerà il piano di esecuzione effettivo che sql ha usato per quella query. Puoi usare quel piano di esecuzione per vedere su quale thread stai aspettando.

Ho anche scoperto che la disattivazione dell'hyper threading ha drasticamente ridotto i tempi di attesa di CXpacket.

Spero possa aiutare.


3

La risposta di cui sopra di Aaron è corretta.

Vorrei solo aggiungere che, se non stai già utilizzando SQL Performance Dashboard Reports e il Data Collector integrato , dovresti iniziare.

Puoi anche prendere la seguente query e modificarla come ritieni opportuno:

DECLARE @MinExecutions int; 
SET @MinExecutions = 5 

SELECT EQS.total_worker_time AS TotalWorkerTime 
      ,EQS.total_logical_reads + EQS.total_logical_writes AS TotalLogicalIO 
      ,EQS.execution_count As ExeCnt 
      ,EQS.last_execution_time AS LastUsage 
      ,EQS.total_worker_time / EQS.execution_count as AvgCPUTimeMiS 
      ,(EQS.total_logical_reads + EQS.total_logical_writes) / EQS.execution_count  
       AS AvgLogicalIO 
      ,DB.name AS DatabaseName 
      ,SUBSTRING(EST.text 
                ,1 + EQS.statement_start_offset / 2 
                ,(CASE WHEN EQS.statement_end_offset = -1  
                       THEN LEN(convert(nvarchar(max), EST.text)) * 2  
                       ELSE EQS.statement_end_offset END  
                 - EQS.statement_start_offset) / 2 
                ) AS SqlStatement 
      -- Optional with Query plan; remove comment to show, but then the query takes !!much longer!! 
      --,EQP.[query_plan] AS [QueryPlan] 
FROM sys.dm_exec_query_stats AS EQS 
     CROSS APPLY sys.dm_exec_sql_text(EQS.sql_handle) AS EST 
     CROSS APPLY sys.dm_exec_query_plan(EQS.plan_handle) AS EQP 
     LEFT JOIN sys.databases AS DB 
         ON EST.dbid = DB.database_id      
WHERE EQS.execution_count > @MinExecutions 
      AND EQS.last_execution_time > DATEDIFF(MONTH, -1, GETDATE()) 
ORDER BY AvgLogicalIo DESC 
        ,AvgCPUTimeMiS DESC

0

Nella mia precedente esperienza Soglia di costo per parallelismo non ha contribuito a ridurre CXPACKET.

CXPACKETUn'attesa elevata può verificarsi a causa di statistiche errate con conseguente parallelismo distorto.

  1. Altro su CXPACKET Waits: Parallelism distorto
  2. Articolo Microsoft Connect
  3. La mia domanda è (non) aspettare a causa del parallelismo? - Tim Ford

Di seguito è riportato SQL che ho usato per trovare sessioni che contengono sia CXPacket che " altre attese " (vedere il dagram di seguito).

SQL

DECLARE @RawResult TABLE ([database_id] INT,[session_id] INT,exec_context_id INT, [blocking_session_id] INT,task_state VARCHAR(20),
                          [cpu_time] BIGINT,[wait_duration_ms] BIGINT, [wait_type] VARCHAR(100),[resource_description] nvarchar(3072),
                          [sql_handle] varbinary(64),[plan_handle] varbinary(64)
                          )
INSERT INTO @RawResult
SELECT 
    [R].[database_id],
    [S].[session_id],
    [W].exec_context_id,
    [W].blocking_session_id,
    [T].task_state,
    [R].[cpu_time],
    [W].[wait_duration_ms],
    [W].[wait_type],
    [W].[resource_description],
    [R].[sql_handle],
    [R].[plan_handle]
FROM sys.dm_os_waiting_tasks [W]
INNER JOIN sys.dm_os_tasks [T] ON
    [W].[waiting_task_address] = [T].[task_address]
INNER JOIN sys.dm_exec_sessions [S] ON
    [W].[session_id] = [S].[session_id]
INNER JOIN sys.dm_exec_requests [R] ON
    [S].[session_id] = [R].[session_id]
WHERE [S].[is_user_process] = 1
--AND S.session_id <> @@SPID--???
--ORDER BY [W].[session_id],[W].[exec_context_id];


SELECT  
    DB_NAME(C.database_id) AS database_name,
    C.[database_id],
    C.[session_id],
    C.exec_context_id,
    C.blocking_session_id,
    C.task_state,
    C.[cpu_time],
    C.[wait_duration_ms],
    C.[wait_type],
    C.[sql_handle],
    C.[plan_handle],
    [H].text,
    [P].[query_plan],
    C.[resource_description]
FROM @RawResult C
OUTER APPLY sys.dm_exec_sql_text (C.[sql_handle]) [H]
OUTER APPLY sys.dm_exec_query_plan (C.[plan_handle]) [P]
WHERE C.[session_id] IN
                    (
                        SELECT A.[session_id]
                        FROM @RawResult A
                        INNER JOIN @RawResult B
                            ON A.[session_id] = B.[session_id]
                            AND A.wait_type='CXPACKET'
                            AND B.wait_type <> 'CXPACKET'
                    )
ORDER BY C.[session_id],C.[exec_context_id]

inserisci qui la descrizione dell'immagine

Anche le scansioni di grandi dimensioni possono far parte della causa principale. Quando ho controllato il piano di esecuzione dalla query sopra, ho trovato una di queste scansioni nel mio database. Mancava anche un suggerimento sull'indice nel piano di esecuzione.

inserisci qui la descrizione dell'immagine


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.