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 |
そのまま実行できるコマンド
- 対象
- 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.
- 対象
- 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.
- 対象
- 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.
- 対象
- 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.
- 対象
- 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_type | Type of wait | Check whether it distinguishes CXPACKET / CXCONSUMER / CXSYNC_PORT, etc. |
| waiting_tasks_count | Number of times this wait occurred | Look at whether it is frequent-but-short or rare-but-long |
| wait_time_ms | Cumulative wait time (including signal wait) | View it relative to instance uptime; the absolute value alone cannot be judged |
| resource_wait_ms | Resource wait time (wait_time_ms − signal_wait_time_ms) | Time actually spent waiting for a resource |
| signal_wait_time_ms | CPU scheduling wait time | A high share of the total suggests CPU saturation |
| pct_of_total | Share of total waits (computed) | Even if CXPACKET ranks high, separately confirm whether it is tied to an actually slow query |
| exec_context_id | Execution context ID of the parallel task | 0 is the coordinator task; if 0 waits for a long time, suspect an uneven workload |
| wait_duration_ms | How long the task is currently waiting | Whether any task is waiting a long time right now |
| dop | The 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
考えられる原因(可能性の高い順)
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.
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.
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.
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.
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.
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
Get the top wait types
参照のみCheck the top 20 by cumulative value to understand where CXPACKET / CXCONSUMER rank.
- 2
Check instance uptime
参照のみCumulative values scale with uptime. Evaluate them alongside `sqlserver_start_time`.
- 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
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
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
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.
バージョン・環境による違い
これで解決しない場合に確認すること
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エージェントと人間の専門家が継続的に監視・運用しています。
How to Check and Change MAXDOP and Cost Threshold for Parallelism in SQL Server
A procedure for checking and changing the degree of parallelism at the server, database, and query levels, along with the differences in scope and impact at each level.
sql-serverSQL to Check Statistics Last-Updated Time per Table in SQL Server
A read-only SQL script using sys.stats and STATS_DATE that lists the last-updated time and the number of rows modified since the last update, per table and statistic.
sql-serverSQL to Check for Long-Running Open Transactions in SQL Server
A procedure using the sys.dm_tran_active_transactions family of DMVs to identify abandoned transactions, including start time, session, and the last SQL statement executed.
monitoringWhat to Configure When Monitoring Servers and Databases 24/7
A checklist, organized by layer, of what to monitor, how to think about thresholds, the escalation structure, and why synthetic monitoring is necessary when designing 24/7 monitoring.
関連サービス
Request an analysis of wait events
同じ確認を複数の環境で継続する必要がある場合は、運用体制ごと相談できます。
Request an analysis of wait events