giip
SES Proposal
SQL Server性能パラメータ監視

Causes and Checks for High CXPACKET Waits in SQL Server

公開日 2026-08-13 · 更新日 2026-08-13 · 最終検証日 2026-08-13

結論

CXPACKET is a wait type representing synchronization between tasks in a parallel query, and a large value by itself is not evidence of a problem. First check its share of total waits using `sys.dm_os_wait_stats`, and on SQL Server 2016 SP2 / 2017 CU3 and later, distinguish it from CXCONSUMER, into which harmless waits were split out. Whether there is actual impact should be judged by watching real-time waits with `sys.dm_os_waiting_tasks` and checking whether they are tied to an actually slow query.

この文書の適用条件

対象製品SQL Server / Amazon RDS for SQL Server / Azure SQL Managed Instance
確認バージョンSQL Server 2008 and later (CXCONSUMER requires SQL Server 2016 SP2 / 2017 CU3 or later)
適用環境On-premises, EC2, Amazon RDS, Azure
必要権限The read-only SQL requires VIEW SERVER STATE. `DBCC SQLPERF(..., CLEAR)` requires server-level permission
実行影響The read-only SQL makes no changes. Clearing wait statistics resets the instance-wide statistics
再起動Not required
最終検証日2026-08-13

そのまま実行できるコマンド

Top 20 wait types (excluding idle-type waits)参照のみ
対象
SQL Server 2008 and later / Amazon RDS for SQL Server
権限
VIEW SERVER STATE
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT TOP (20)
    ws.wait_type,
    ws.waiting_tasks_count,
    ws.wait_time_ms,
    ws.wait_time_ms - ws.signal_wait_time_ms AS resource_wait_ms,
    ws.signal_wait_time_ms,
    ws.max_wait_time_ms,
    CAST(100.0 * ws.wait_time_ms
         / NULLIF(SUM(ws.wait_time_ms) OVER (), 0) AS decimal(5, 2)) AS pct_of_total
FROM sys.dm_os_wait_stats AS ws
WHERE ws.waiting_tasks_count > 0
  -- 常時発生するアイドル・バックグラウンド待機を除外する
  AND ws.wait_type NOT IN (
        'CLR_SEMAPHORE', 'LAZYWRITER_SLEEP', 'RESOURCE_QUEUE', 'SLEEP_TASK',
        'SLEEP_SYSTEMTASK', 'SQLTRACE_BUFFER_FLUSH', 'WAITFOR', 'LOGMGR_QUEUE',
        'CHECKPOINT_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH', 'XE_TIMER_EVENT',
        'BROKER_TO_FLUSH', 'BROKER_TASK_STOP', 'CLR_MANUAL_EVENT', 'CLR_AUTO_EVENT',
        'DISPATCHER_QUEUE_SEMAPHORE', 'FT_IFTS_SCHEDULER_IDLE_WAIT',
        'XE_DISPATCHER_WAIT', 'XE_DISPATCHER_JOIN', 'ONDEMAND_TASK_QUEUE',
        'BROKER_EVENTHANDLER', 'SLEEP_BPOOL_FLUSH', 'DIRTY_PAGE_POLL',
        'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', 'SP_SERVER_DIAGNOSTICS_SLEEP',
        'QDS_ASYNC_QUEUE', 'HADR_FILESTREAM_IOMGR_IOCOMPLETION'
      )
ORDER BY ws.wait_time_ms DESC;

`sys.dm_os_wait_stats` is a cumulative total since the instance started (or since it was last explicitly cleared). The waits in the exclusion list occur almost constantly as idle-type waits, so without excluding them they would fill up the top results. Even if CXPACKET ranks high in `pct_of_total`, that alone does not indicate a problem.

Check when statistics collection started (instance start time)参照のみ
対象
SQL Server 2012 and later (`sqlserver_start_time` column)
権限
VIEW SERVER STATE
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2012 以降(sqlserver_start_time 列)
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
    sqlserver_start_time,
    DATEDIFF(HOUR, sqlserver_start_time, GETDATE()) AS uptime_hours
FROM sys.dm_os_sys_info;

Cumulative wait time grows in proportion to uptime. Do not conclude "CXPACKET is high" just by looking at the cumulative total for an instance that has been up for months. You need to look at the value per hour of uptime, or at the interval-based delta described below.

Real-time parallel waits (CXPACKET / CXCONSUMER)参照のみ
対象
SQL Server 2008 and later (the `dop` column requires SQL Server 2016 or later)
権限
VIEW SERVER STATE
変更作業
None (read-only)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降(dop 列は SQL Server 2016 以降)
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(参照のみ)
-- Production 実行: 可能
SELECT
    wt.session_id,
    wt.exec_context_id,
    wt.wait_type,
    wt.wait_duration_ms,
    wt.blocking_session_id,
    wt.blocking_exec_context_id,
    wt.resource_description,
    r.status,
    r.command,
    r.dop,                       -- SQL Server 2016 以降。それ以前の版では列を外すこと
    r.total_elapsed_time,
    txt.text                     AS batch_text
FROM sys.dm_os_waiting_tasks AS wt
LEFT JOIN sys.dm_exec_requests AS r
       ON wt.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS txt
WHERE wt.wait_type LIKE 'CX%'
ORDER BY wt.session_id, wt.exec_context_id;

`exec_context_id = 0` is the coordinator task for the parallel query, and all other values are parallel workers. A coordinator task waiting for a long time suggests the work may be unevenly distributed across workers (skew). The point of this query is to see whether something is waiting right now, not the cumulative total.

Measure wait statistics as a delta over an interval (without clearing them)参照のみ
対象
SQL Server 2008 and later / Amazon RDS for SQL Server
権限
VIEW SERVER STATE
変更作業
None (only creates a temp table)
Production実行
Safe to run
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: VIEW SERVER STATE
-- 変更作業: なし(セッションスコープの一時テーブルのみ)
-- Production 実行: 可能
-- 1) 計測開始時点のスナップショットを取る
SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms
INTO #wait_snapshot
FROM sys.dm_os_wait_stats;

-- 2) 計測したい時間だけ待つ(例: 10分)
WAITFOR DELAY '00:10:00';

-- 3) 差分を取る
SELECT TOP (20)
    w.wait_type,
    w.waiting_tasks_count - s.waiting_tasks_count AS delta_tasks,
    w.wait_time_ms        - s.wait_time_ms        AS delta_wait_ms,
    w.signal_wait_time_ms - s.signal_wait_time_ms AS delta_signal_ms
FROM sys.dm_os_wait_stats AS w
INNER JOIN #wait_snapshot AS s
        ON w.wait_type = s.wait_type
WHERE w.wait_time_ms - s.wait_time_ms > 0
ORDER BY delta_wait_ms DESC;

DROP TABLE #wait_snapshot;

This lets you measure "wait trends during a specific window" without clearing the instance-wide statistics, so prefer this approach in production. It does not affect measurements taken by other operations or monitoring tools.

Clear wait statistics (affects the whole instance)
対象
SQL Server 2008 and later / Amazon RDS for SQL Server
権限
Server-level permission (equivalent to sysadmin)
変更作業
Yes (resets the instance-wide wait statistics to zero)
Production実行
Not recommended — also affects other monitoring tools' measurements
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: サーバーレベルの権限(sysadmin 相当)
-- 変更作業: あり(インスタンス全体の待機統計をリセット)
-- Production 実行: 推奨しない。差分計測で代替できないか先に検討すること
DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);

No data is lost, but the instance-wide cumulative wait statistics reset to zero. If other monitoring tools reference the same instance, or operations rely on comparison against past values, that baseline disappears. If the delta-measurement approach above meets your needs, use that instead.

結果の読み方

意味確認するポイント
wait_typeType of waitCheck whether it distinguishes CXPACKET / CXCONSUMER / CXSYNC_PORT, etc.
waiting_tasks_countNumber of times this wait occurredLook at whether it is frequent-but-short or rare-but-long
wait_time_msCumulative wait time (including signal wait)View it relative to instance uptime; the absolute value alone cannot be judged
resource_wait_msResource wait time (wait_time_ms − signal_wait_time_ms)Time actually spent waiting for a resource
signal_wait_time_msCPU scheduling wait timeA high share of the total suggests CPU saturation
pct_of_totalShare of total waits (computed)Even if CXPACKET ranks high, separately confirm whether it is tied to an actually slow query
exec_context_idExecution context ID of the parallel task0 is the coordinator task; if 0 waits for a long time, suspect an uneven workload
wait_duration_msHow long the task is currently waitingWhether any task is waiting a long time right now
dopThe actual degree of parallelism for the request (SQL Server 2016 and later)Whether the degree of parallelism is higher than expected

こういう状況で使います

  • When wait statistics are aggregated, CXPACKET is consistently near the top
  • CPU usage is high, but individual query throughput does not improve
  • The same query takes wildly different amounts of time from one run to the next
  • Overall responsiveness degrades specifically during periods of high concurrency

考えられる原因(可能性の高い順)

  1. 01

    This is not actually a problem (parallel execution is working as intended)

    CXPACKET necessarily occurs whenever tasks in a parallel query synchronize with each other. In systems with a lot of analytical queries, it is normal for it to rank high, and ranking high by itself does not indicate a problem. Rule this out first.

  2. 02

    Cost Threshold for Parallelism is too low, causing even small queries to go parallel

    The default value of 5 dates back to a very different era of hardware. In many environments, leaving it at this value causes queries that gain little from parallelism to get parallel plans anyway, adding coordination overhead with little benefit. That said, the right value depends on the workload and should not be changed without measurement.

  3. 03

    Workload is unevenly distributed across parallel workers (skew)

    In partitioned processing, if one worker handles a disproportionate number of rows, the other workers sit idle waiting. You can confirm this from the row-count distribution across threads in the actual execution plan.

  4. 04

    Outdated statistics are causing an unnecessarily large parallel plan to be chosen

    If the estimated row count is larger than the actual count, the estimated cost comes out higher, leading to a parallel plan. The fix here is updating statistics, not changing the degree of parallelism.

  5. 05

    Missing indexes are causing a large scan to be parallelized

    Without a suitable index, the query scans the entire table, and that scan is parallelized. Redesigning the index can eliminate the need for parallel execution altogether.

  6. 06

    The CPU is saturated

    If the share of `signal_wait_time_ms` is high, what's being waited on is not a resource but CPU scheduling order. Lowering the degree of parallelism can help, but the root cause is insufficient CPU or query inefficiency.

確認手順

  1. 1

    Get the top wait types

    参照のみ

    Check the top 20 by cumulative value to understand where CXPACKET / CXCONSUMER rank.

  2. 2

    Check instance uptime

    参照のみ

    Cumulative values scale with uptime. Evaluate them alongside `sqlserver_start_time`.

  3. 3

    Measure a delta for the relevant time window

    参照のみ

    Take a snapshot delta during the window when the problem occurs to produce wait trends specific to that window.

  4. 4

    Identify an actually slow query

    If no slow query exists, no action is needed even if CXPACKET ranks high. Capture the slow query's execution plan before proceeding.

  5. 5

    Observe real-time parallel waits

    参照のみ

    Check `CX%` waits with `sys.dm_os_waiting_tasks` and see whether the coordinator task (`exec_context_id = 0`) is waiting for a long time.

  6. 6

    Check statistics and indexes

    参照のみ

    Check for a gap between estimated and actual row counts, and for any large scans. Only touch the degree-of-parallelism setting after this.

対応方法

すぐに実施できる低リスクの対応

  • Confirm whether there is real impact, and do nothing if there is none

    参照のみ

    Even if CXPACKET ranks high, no action is needed if every query is meeting its target time. Flattening the ranking of wait statistics is not, by itself, a goal.

  • Update statistics

    If an unnecessary parallel plan was chosen due to a row-count estimation gap, updating statistics can change the plan. Check this before touching degree-of-parallelism settings.

  • Restrict the degree of parallelism for a specific query only

    If the problem is limited to specific queries, control just those with `OPTION (MAXDOP n)`. This has no effect on the rest of the server.

事前検討が必要な変更

  • Review Cost Threshold for Parallelism

    Consider this once measurement confirms that even small queries are being parallelized. The right value depends on the workload, so decide by comparing execution plans and response times before and after the change.

  • Review MAXDOP

    Set an upper bound on the degree of parallelism at the server or database level. Because this changes execution plans server-wide, apply it gradually and measure the effect.

  • Redesign indexes

    Where a large scan is being parallelized, adding a suitable index can eliminate the need for parallel execution entirely.

再起動・サービス影響を伴う変更

  • Clear wait statistics and re-measure

    This resets the instance-wide cumulative statistics and destroys the baseline other monitoring tools rely on. Check first whether delta measurement can serve the same purpose.

  • Control the degree of parallelism with Resource Governor

    専門家レビュー必須

    You can control the degree of parallelism per workload group, but a misconfiguration can make a specific workload extremely slow. This also has edition restrictions, so it assumes a design review.

!注意事項

  • CXPACKET ranking high among waits is not, by itself, evidence of a problem. The simplistic response of "CXPACKET is high, so set MAXDOP to 1" can drastically slow down analytical workloads that were functioning fine under parallel execution.
  • From SQL Server 2016 SP2 / 2017 CU3 onward, some harmless waits during parallel execution were split out as CXCONSUMER. On these versions and later, do not treat CXCONSUMER the same as CXPACKET.
  • `sys.dm_os_wait_stats` is cumulative since the instance started. Comparing absolute values between instances with different uptimes is meaningless.
  • `DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)` resets the instance-wide statistics. This also affects any other monitoring tool referencing the same instance.
  • Changing degree-of-parallelism settings affects execution plans across the entire server. Do not make lowering the CXPACKET figure itself the goal.

バージョン・環境による違い

SQL Server 2016 SP2 / 2017 CU3 and laterParallel execution waits were split into CXPACKET and CXCONSUMER. CXCONSUMER represents waits on the consumer-side thread and is generally considered harmless. On these versions and later, evaluate the two separately.
SQL Server 2016 and later`sys.dm_exec_requests` has a `dop` column showing the actual degree of parallelism per request. On earlier versions, remove this column from the query.
SQL Server 2012 and later`sys.dm_os_sys_info.sqlserver_start_time` gives the instance start time, which serves as the baseline for evaluating cumulative wait time.
Amazon RDS for SQL ServerThe wait-statistics DMVs can be queried as-is. Changing MAXDOP or Cost Threshold goes through a DB parameter group, so the procedure differs.

これで解決しない場合に確認すること

  • Row-count distribution across threads in the execution plan

    Check the actual execution plan for a significant imbalance in row counts across parallel threads — an imbalance indicates skew.

  • CPU usage and scheduler state

    Check `runnable_tasks_count` in `sys.dm_os_schedulers` to see whether the CPU run queue is backing up.

  • PAGEIOLATCH-family waits

    If I/O waits also rank high alongside CXPACKET, the root cause may lie on the storage side.

  • Memory grant waits (RESOURCE_SEMAPHORE)

    Parallel queries request larger memory grants. If this wait co-occurs, memory also needs to be examined.

この文書の根拠と限界

製品の公式ドキュメントに基づく説明

A general procedure based on the public specifications of SQL Server's `sys.dm_os_wait_stats`, `sys.dm_os_waiting_tasks`, `sys.dm_exec_requests`, `sys.dm_os_sys_info`, and `DBCC SQLPERF`. The CXCONSUMER introduction is described as SQL Server 2016 SP2 / 2017 CU3, but check the version details of the target environment for the exact applicable build. It does not include measured values from any specific customer.

よくある質問

Is a high volume of CXPACKET waits a problem?

Ranking high among waits is not, by itself, a problem. CXPACKET is evidence that parallel queries are running, and it is normal for it to rank high in environments with a lot of analytical workloads. It only becomes something to act on once there is a process actually exceeding its target time that is tied to this parallel wait.

What is the difference between CXPACKET and CXCONSUMER?

From SQL Server 2016 SP2 / 2017 CU3 onward, the consumer-side thread wait within parallel execution was split out as CXCONSUMER. CXCONSUMER is generally considered harmless, and treating it the same as CXPACKET leads to overreaction.

Can this be run in production?

The read-only SQL and the delta measurement can both be run in production. `DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)` resets the instance-wide statistics, so it is not recommended in production — use delta measurement instead.

Does this work on AWS RDS?

The wait-statistics DMVs (`sys.dm_os_wait_stats`, `sys.dm_os_waiting_tasks`) can be queried as-is on Amazon RDS for SQL Server. However, since changing the degree of parallelism goes through a DB parameter group, procedures that assume `sp_configure` cannot be used as written.

What permissions are required?

The read-only SQL requires VIEW SERVER STATE. Clearing wait statistics requires server-level permission (equivalent to sysadmin), which may not be available on a managed service.

How should I interpret the results?

Evaluate by the delta during the window when the problem occurs, not by the ranking of cumulative values. From there, move on to reviewing the degree of parallelism only if the slow query's execution plan has a parallel operator and the row counts are unevenly distributed across threads.

この文書がカバーする質問

  • I want to know whether CXPACKET ranking high among waits is abnormal
  • I want to know how to read wait events
  • I want to check parallel query waits while they are happening

リスク表示の意味

  • 参照のみデータと設定を変更しません。
  • 影響は限定的ですが、権限と負荷の確認が必要です。
  • 性能・ロック・コストに影響する可能性があります。
  • 障害・データ損失・復旧作業が発生する可能性があります。
  • 専門家レビュー必須本番適用前に別途レビューが必須です。

GIIPの対応範囲

Wait events like CXPACKET are a metric best judged not by a single snapshot but by "how does this compare to normal." At GIIP, wait statistics are periodically captured as snapshots and accumulated in a form that supports comparing deltas across time windows. An AI agent detects deviations from the normal pattern and escalates to a human only when tied to an actually slowed-down query, avoiding number-first judgments like "CXPACKET ranks high, so lower the degree of parallelism."

執筆・技術検証

GIIP プロダクション運用チーム

大規模Webサービス、SQL Server、Oracle、AWS、Azureの設計・移行・運用に約30年従事。x12largeクラスのAWS RDS for SQL Server環境12セット、約12万テーブルのOracle環境、約3TBのTiDBからAurora MySQLへの移行を経験。現在も複数のクラウドデータベースと約30のWebサービスを、AIエージェントと人間の専門家が継続的に監視・運用しています。

関連するナレッジ

関連サービス

Request an analysis of wait events

同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。

Request an analysis of wait events

ナレッジベース一覧へ