Der Umgang mit CXPACKET wartet - Festlegung der Kostenschwelle für Parallelität

12

Als Antwort auf meine vorherige Frage zur Fehlerbehebung bei einer Sharepoint-Site habe ich mich gefragt, ob ich etwas gegen die CXPACKET-Wartezeiten unternehmen kann.

Ich weiß, die Lösung ist, alle Parallelität auszuschalten, indem MAXDOP auf 1 gesetzt wird - das klingt nach einer schlechten Idee. Eine andere Idee ist es, die Kostenschwelle zu erhöhen, bevor die Parallelität einsetzt. Der Standardwert von 5 für die Kosten eines Ausführungsplans ist relativ niedrig.

Ich habe mich gefragt, ob es da draußen bereits eine Abfrage gibt, die mir die Abfragen mit den höchsten Ausführungsplankosten aufzeigt (ich weiß, dass Sie die Abfragen mit der höchsten Ausführungsdauer usw. finden können. Ist die Ausführungsplankosten jedoch irgendwo abrufbar?). auch?) und das würde mir auch sagen, ob eine solche Abfrage parallel ausgeführt wurde.

Hat jemand ein solches Skript zur Hand oder kann er mich in die Richtung der relevanten DMV-, DMF- oder anderen Systemkatalogansichten lenken, um dies herauszufinden?

marc_s
quelle

Antworten:

11

CXPACKETist nie ein Grund; es wird alles beschuldigt, aber es ist immer ein Symptom für etwas anderes. Sie müssen diese Fragen sofort beantworten und herausfinden, was "etwas anderes" ist. Dies kann von Abfrage zu Abfrage unterschiedlich sein, und das Deaktivieren der Parallelität ist - wie Sie vorgeschlagen haben - in den meisten Fällen unnötiger Overkill. Aber es ist oft der geringste Arbeitsaufwand, weshalb es sich um einen so weit verbreiteten "Fix" handelt.

Wenn Sie einen tatsächlichen Plan für eine Abfrage erhalten, die anscheinend für hohe CXPACKET-Wartezeiten verantwortlich ist, laden Sie ihn in den SQL Sentry Plan Explorer . Es gibt normalerweise einen Grund dafür; Wir zeigen, welche parallelen Operationen zu einem Thread-Versatz geführt haben, und Sie können dies leicht mit Schätzungen korrelieren, die um einen bestimmten Schwellenwert abweichen. Normalerweise sind die zugrunde liegenden Probleme wirklich schlechte / veraltete (oder nicht verfügbare) Statistiken.

Leider handelt es sich bei sys.dm_exec_cached_plans um geschätzte Pläne. Sie werden Ihnen nicht sagen, ob der Plan parallel lief, als er tatsächlich verwendet wurde, da der tatsächliche Plan nicht im Cache gespeichert ist. In einigen Fällen wird erwartet, dass sowohl ein serieller als auch ein paralleler Plan für dieselbe Abfrage angezeigt wird. Auf diese Weise geht SQL Server nicht mit der Situation für parallele Pläne um, die zur Laufzeit möglicherweise parallel sind. ( Viele Informationen dazu hier .)

Aaron Bertrand
quelle
4

Wenn Sie den tatsächlichen Ausführungsplan einer laufenden Abfrage anzeigen möchten.

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

Tragen Sie dann zuerst das Ergebnis in diese Abfrage ein.

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

Das zeigt Ihnen den tatsächlichen Ausführungsplan, den SQL für diese Abfrage verwendet hat. Sie können diesen Ausführungsplan verwenden, um festzustellen, auf welchen Thread Sie warten.

Ich habe auch festgestellt, dass das Deaktivieren von Hyper-Threading die Wartezeiten für CXpacket drastisch verkürzt.

Ich hoffe, das hilft.

Zane
quelle
3

Die obige Antwort von Aaron ist richtig.

Ich würde einfach so hinzufügen, wenn Sie nicht bereits mit SQL Performance Dashboard - Berichten und die Einbau- Data Collector , sollten Sie beginnen.

Sie können auch die folgende Abfrage ausführen und sie nach Belieben ändern:

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
quelle
0

Nach meiner bisherigen Erfahrung hat Cost Threshold For Parallelism nicht dazu beigetragen, CXPACKET zu reduzieren.

Eine hohe CXPACKETWartezeit kann aufgrund falscher Statistiken auftreten, die zu einer verzerrten Parallellität führen.

  1. Weitere Informationen zu CXPACKET Waits: Schräge Parallelität
  2. Microsoft Connect-Objekt
  3. Meine Abfrage wartet (nicht) wegen Parallelität? - Tim Ford

Das Folgende ist SQL, das ich verwendet habe, um Sitzungen zu finden, in denen sowohl CXPacket als auch " other waits " enthalten sind (siehe Abbildung unten).

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]

Bildbeschreibung hier eingeben

Große Scans können ebenfalls Teil der Grundursache sein. Als ich den Ausführungsplan anhand der obigen Abfrage überprüfte, fand ich einen solchen Scan in meiner Datenbank. Es fehlte auch ein Indexvorschlag im Ausführungsplan.

Bildbeschreibung hier eingeben


LCJ
quelle