Tratar con las esperas de CXPACKET: establecer el umbral de costo para el paralelismo

12

Como seguimiento a mi pregunta anterior sobre la solución de problemas de rendimiento de un sitio de Sharepoint , me preguntaba si podría hacer algo con respecto a las esperas de CXPACKET.

Sé que la solución instintiva es desactivar todo paralelismo estableciendo MAXDOP en 1, parece una mala idea. Pero otra idea es aumentar el umbral de costo antes de que entre en juego el paralelismo. El valor predeterminado de 5 para el costo de un plan de ejecución es bastante bajo.

Entonces, me preguntaba si ya hay una consulta por escrito que pueda encontrarme las consultas con el costo de plan de ejecución más alto (sé que puede encontrar las que tienen la duración de ejecución más alta, etc.), pero ¿puede recuperarse el costo del plan de ejecución en alguna parte? también?) y eso también me diría si tal consulta se ha ejecutado en paralelo.

¿Alguien tiene una secuencia de comandos a mano, o puede señalarme en la dirección del DMV, DMF u otras vistas de catálogo del sistema relevantes para descubrir esto?

marc_s
fuente

Respuestas:

11

CXPACKETnunca es una causa; tiene toda la culpa, pero siempre es un síntoma de otra cosa. Necesita captar estas consultas en el acto y descubrir qué es "otra cosa". Puede ser diferente de una consulta a otra, y desactivar el paralelismo por completo es, como ha sugerido, una exageración innecesaria en la mayoría de los casos. Pero a menudo es la menor cantidad de trabajo, razón por la cual es una "solución" tan frecuente.

Si puede obtener un plan real para una consulta que parece ser responsable de las altas esperas de CXPACKET, cárguelo en SQL Sentry Plan Explorer . Generalmente hay una razón detrás de esto; mostramos qué operaciones paralelas condujeron a un sesgo de subprocesos, y puede correlacionarlo fácilmente con las estimaciones que están desactivadas (destacamos las operaciones con estimaciones que están desactivadas en un umbral al menos determinado). Por lo general, el problema subyacente son las estadísticas realmente malas / desactualizadas (o no disponibles).

Lamentablemente, lo que encontrará en sys.dm_exec_cached_plans son planes estimados . No le dirán si el plan fue paralelo cuando se usó realmente, porque el plan real no es lo que está en caché. En algunos casos, espera ver un plan en serie y paralelo para la misma consulta; No es así como SQL Server trata la situación de los planes paralelos que podrían ser paralelos en tiempo de ejecución. ( Mucha información sobre eso aquí .)

Aaron Bertrand
fuente
4

Si desea ver el plan de ejecución real de una consulta que se está ejecutando.

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

Primero ingrese el resultado en esta consulta.

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

Eso le mostrará el plan de ejecución real que sql usó para esa consulta. Podría usar ese plan de ejecución para ver qué hilo está esperando.

También descubrí que desactivar el hiperprocesamiento reduce drásticamente los tiempos de espera de mi CXpacket.

Espero que ayude.

Zane
fuente
3

La respuesta anterior de Aaron es correcta.

Solo me gustaría agregar eso, si aún no está utilizando SQL Performance Dashboard Reports y el recopilador de datos incorporado , debería comenzar.

También puede tomar la siguiente consulta y modificarla como mejor le parezca:

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
tacotuesday
fuente
0

En mi experiencia previa, el Umbral de costo para paralelismo no ayudó a reducir CXPACKET.

La CXPACKETespera alta puede suceder debido a estadísticas incorrectas que resultan en paralelismo sesgado.

  1. Más información sobre CXPACKET Waits: Skewed Parallelism
  2. Artículo de Microsoft Connect
  3. Mi consulta está (no) en espera debido al paralelismo - Tim Ford

El siguiente es el SQL que solía encontrar sesiones que tienen tanto CXPacket como " otras esperas " (consulte el dagrama a continuación).

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]

ingrese la descripción de la imagen aquí

Los escaneos grandes también pueden ser parte de la causa raíz. Cuando revisé el plan de ejecución de la consulta anterior, encontré uno de esos escaneos en mi base de datos. También faltaba una sugerencia de índice en el plan de ejecución.

ingrese la descripción de la imagen aquí


LCJ
fuente