Работа с CXPACKET ждет - установка порога стоимости для параллелизма

12

В качестве продолжения моего предыдущего вопроса о поиске и устранении неисправностей на сайте Sharepoint , мне было интересно, могу ли я что-то сделать с ожиданиями CXPACKET.

Я знаю, что решение коленного рывка состоит в том, чтобы отключить весь параллелизм, установив MAXDOP в 1 - звучит как плохая идея. Но другая идея состоит в том, чтобы увеличить порог стоимости до того, как начнется параллелизм. Значение по умолчанию 5 для плана выполнения довольно низкое.

Поэтому мне было интересно, есть ли уже написанный запрос, который найдет мне запросы с самой высокой стоимостью плана выполнения (я знаю, что вы можете найти запросы с самой высокой продолжительностью выполнения и т. Д.), Но можно ли получить стоимость плана выполнения где-нибудь, тоже?) и это также скажет мне, если такой запрос был выполнен параллельно.

Кто-нибудь имеет такой сценарий под рукой, или может указать мне направление соответствующих DMV, DMF или других представлений системного каталога, чтобы выяснить это?

marc_s
источник

Ответы:

11

CXPACKETникогда не является причиной; это обвиняет всех, но это всегда симптом чего-то другого. Вам нужно поймать эти запросы в действии и выяснить, что такое «что-то еще». Он может отличаться от запроса к запросу, и отключение параллелизма в целом - как вы и предполагали - в большинстве случаев является излишним излишним. Но зачастую это наименьший объем работы, поэтому он является таким распространенным «исправлением».

Если вы можете получить реальный план для запроса, который, по-видимому, отвечает за ожидания CXPACKET, загрузите его в SQL Sentry Plan Explorer . За этим обычно стоит причина; мы показываем, какие параллельные операции привели к перекосу потока, и вы можете легко соотнести это с оценками, которые отключены (мы выделяем операции с оценками, которые отключены по крайней мере на определенное пороговое значение). Обычно основной проблемой является действительно плохая / устаревшая (или недоступная) статистика.

К сожалению, то, что вы найдете в sys.dm_exec_cached_plans, является приблизительным планом. Они не скажут вам, был ли план параллельным, когда он фактически использовался, потому что фактический план не является тем, что кэшируется. В некоторых случаях вы ожидаете увидеть как последовательный, так и параллельный план для одного и того же запроса; Это не то, как SQL Server справляется с ситуацией для параллельных планов, которые могут быть параллельными во время выполнения. ( Много информации об этом здесь .)

Аарон Бертран
источник
4

Если вы хотите увидеть фактический план выполнения запроса, который выполняется.

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

Сначала введите результат в этот запрос.

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

Это покажет вам фактический план выполнения, который sql использовал для этого запроса. Вы можете использовать этот план выполнения, чтобы увидеть, какой поток вы ожидаете.

Я также обнаружил, что отключение гиперпоточности резко сократило время ожидания моего CXpacket.

Надеюсь, это поможет.

Зейн
источник
3

Приведенный выше ответ Аарона является правильным.

Я просто хотел бы добавить, что, если вы еще не используете Отчеты панели мониторинга производительности SQL и встроенный сборщик данных , вам следует начать.

Вы также можете взять следующий запрос и изменить его так, как считаете нужным:

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
источник
0

В моем предыдущем опыте Cost Threshold For Parallelism не помог уменьшить CXPACKET.

Высокое CXPACKETожидание может произойти из-за неверной статистики, приводящей к перекосу параллелизма.

  1. Подробнее о CXPACKET Waits: перекос параллелизма
  2. Microsoft Connect Item
  3. Мой запрос (не) ждет из-за параллелизма? - Тим Форд

Ниже приведен SQL, который я использовал для поиска сеансов, в которых есть как CXPacket, так и « другие ожидания » (см. Схему ниже).

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]

введите описание изображения здесь

Большие сканы также могут быть частью первопричины. Когда я проверил план выполнения из вышеприведенного запроса, я нашел одно такое сканирование в своей базе данных. В плане выполнения также отсутствовало указание на индекс.

введите описание изображения здесь


LCJ
источник