giip
SES案件登録
SQL Server性能パラメータ監視

SQL ServerでCXPACKET待機が多いときの原因と確認方法

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

結論

CXPACKET は並列クエリの各タスク間の同期待ちを表す待機で、値が大きいこと自体は障害の証拠になりません。まず `sys.dm_os_wait_stats` で全待機に占める割合を確認し、SQL Server 2016 SP2 / 2017 CU3 以降であれば無害な待機が分離された CXCONSUMER と区別してください。実害があるかどうかは、`sys.dm_os_waiting_tasks` でリアルタイムの待機を見て、実際に遅いクエリと結び付いているかで判断します。

この文書の適用条件

対象製品SQL Server / Amazon RDS for SQL Server / Azure SQL Managed Instance
確認バージョンSQL Server 2008 以降(CXCONSUMER は SQL Server 2016 SP2 / 2017 CU3 以降)
適用環境オンプレミス、EC2、Amazon RDS、Azure
必要権限参照用SQLは VIEW SERVER STATE。`DBCC SQLPERF(..., CLEAR)` はサーバーレベルの権限が必要
実行影響参照用SQLは変更なし。待機統計のクリアはインスタンス全体の統計値をリセットします
再起動不要
最終検証日2026-08-13

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

待機事象の上位20件(アイドル系待機を除外)参照のみ
対象
SQL Server 2008 以降 / Amazon RDS for SQL Server
権限
VIEW SERVER STATE
変更作業
なし(参照のみ)
Production実行
可能
-- 対象: 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` はインスタンス起動時(または明示的なクリア時)からの累計値です。除外リストに載せた待機はほぼ常時発生するアイドル系のため、除かないと上位が埋まります。CXPACKET の `pct_of_total` が上位でも、それだけでは問題とは言えません。

統計の集計開始時点を確認する(インスタンス起動時刻)参照のみ
対象
SQL Server 2012 以降(`sqlserver_start_time` 列)
権限
VIEW SERVER STATE
変更作業
なし(参照のみ)
Production実行
可能
-- 対象: 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;

累計待機時間は稼働時間に比例して増えます。起動から数か月経過したインスタンスの累計値だけを見て「CXPACKET が多い」と判断しないでください。稼働時間で割った1時間あたりの値、または後述の期間差分で見る必要があります。

リアルタイムの並列待機(CXPACKET / CXCONSUMER)参照のみ
対象
SQL Server 2008 以降(`dop` 列は SQL Server 2016 以降)
権限
VIEW SERVER STATE
変更作業
なし(参照のみ)
Production実行
可能
-- 対象: 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` が並列クエリの調整タスク(コーディネーター)で、それ以外が並列ワーカーです。調整タスクが長く待っている状態は、ワーカー間で処理量が偏っている(スキュー)可能性を示します。累計値ではなく「今この瞬間に待っているか」を見るのがこのクエリの目的です。

待機統計を期間で差分計測する(クリアせずに測る方法)参照のみ
対象
SQL Server 2008 以降 / Amazon RDS for SQL Server
権限
VIEW SERVER STATE
変更作業
なし(一時テーブルの作成のみ)
Production実行
可能
-- 対象: 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;

インスタンス全体の統計をクリアせずに「特定の時間帯だけの待機傾向」を測れるため、本番環境ではこちらを優先してください。他の運用・監視ツールの計測値にも影響しません。

待機統計のクリア(インスタンス全体に影響)
対象
SQL Server 2008 以降 / Amazon RDS for SQL Server
権限
サーバーレベルの権限(sysadmin 相当)
変更作業
あり(インスタンス全体の待機統計を0にリセット)
Production実行
推奨しない。他の監視ツールの計測値にも影響する
-- 対象: SQL Server 2008 以降 / Amazon RDS for SQL Server
-- 権限: サーバーレベルの権限(sysadmin 相当)
-- 変更作業: あり(インスタンス全体の待機統計をリセット)
-- Production 実行: 推奨しない。差分計測で代替できないか先に検討すること
DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR);

データは失われませんが、インスタンス全体の累計待機統計が0に戻ります。同じインスタンスを参照している他の監視ツールや、過去との比較を前提とした運用がある場合、その基準が消えます。差分計測(前掲)で目的を満たせるなら、そちらを使ってください。

結果の読み方

意味確認するポイント
wait_type待機の種類CXPACKET / CXCONSUMER / CXSYNC_PORT などの区別を確認する
waiting_tasks_countその待機が発生した回数回数が多く1回あたりが短いのか、回数は少ないが1回が長いのかを見る
wait_time_ms待機の累計時間(シグナル待ちを含む)インスタンス稼働時間に対する比率で見る。絶対値だけでは判断できない
resource_wait_msリソース待ち時間(wait_time_ms − signal_wait_time_ms)実際にリソースを待っていた時間
signal_wait_time_msCPUスケジュール待ち時間全体に占める比率が高い場合、CPU の飽和を疑う
pct_of_total全待機に占める割合(算出値)CXPACKET が上位でも、実際に遅いクエリと結び付くかを別途確認する
exec_context_id並列タスクの実行コンテキストID0 が調整タスク。0 が長く待つ場合は処理量の偏りを疑う
wait_duration_ms現在待機している時間リアルタイムで長時間待っているタスクがあるか
dopそのリクエストの実際の並列度(SQL Server 2016 以降)想定より高い並列度になっていないか

こういう状況で使います

  • 待機事象を集計すると CXPACKET が常に上位に来る
  • CPU 使用率は高いのに、個々のクエリのスループットが上がらない
  • 同じクエリでも実行するたびに所要時間が大きくばらつく
  • 同時実行数が増える時間帯だけ全体的に応答が遅くなる

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

  1. 01

    そもそも問題ではない(並列実行が正常に機能している)

    CXPACKET は並列クエリのタスク間同期で必ず発生します。分析系クエリが多いシステムでは上位に来るのが普通で、上位であること自体は異常を意味しません。まずこの可能性を排除してください。

  2. 02

    Cost Threshold for Parallelism が低く、小さいクエリまで並列化されている

    既定値の 5 は非常に古い時代の基準です。多くの環境ではこの値のままだと、並列化の恩恵が小さいクエリまで並列プランになり、調整コストだけが増えます。ただし適正値はワークロード次第で、計測なしに変更すべきではありません。

  3. 03

    並列ワーカー間の処理量が偏っている(スキュー)

    パーティション化された処理で特定のワーカーだけが大量の行を処理すると、他のワーカーが待ち続けます。実行プランの各スレッドの行数分布で確認できます。

  4. 04

    統計情報が古く、不要に大きな並列プランが選ばれている

    推定行数が実際より大きいと、コストが高く見積もられて並列プランが選ばれます。この場合の対処は並列度設定ではなく統計情報の更新です。

  5. 05

    インデックスが不足し、大規模スキャンが並列化されている

    適切なインデックスがないためテーブル全体をスキャンし、そのスキャンが並列化されている状態です。インデックス設計の見直しで並列実行自体が不要になります。

  6. 06

    CPU が飽和している

    `signal_wait_time_ms` の比率が高い場合、待っているのはリソースではなく CPU のスケジュール順です。並列度を下げると改善することがありますが、根本原因は CPU 不足またはクエリ効率です。

確認手順

  1. 1

    待機事象の上位を取得する

    参照のみ

    累計値の上位20件を確認し、CXPACKET / CXCONSUMER の位置づけを把握します。

  2. 2

    インスタンス稼働時間を確認する

    参照のみ

    累計値は稼働時間に比例します。`sqlserver_start_time` と併せて評価します。

  3. 3

    対象時間帯で差分計測する

    参照のみ

    問題が起きる時間帯にスナップショットの差分を取り、その時間帯だけの待機傾向を出します。

  4. 4

    実際に遅いクエリを特定する

    遅いクエリが存在しないなら、CXPACKET が上位でも対応は不要です。遅いクエリの実行プランを取得してから次に進みます。

  5. 5

    リアルタイムの並列待機を観測する

    参照のみ

    `sys.dm_os_waiting_tasks` で `CX%` の待機を確認し、調整タスク(`exec_context_id = 0`)が長く待っていないかを見ます。

  6. 6

    統計情報とインデックスを確認する

    参照のみ

    推定行数と実際の行数の乖離、および大規模スキャンの有無を確認します。並列度設定を触るのはこの後です。

対応方法

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

  • 実害の有無を確認して、無いなら何もしない

    参照のみ

    CXPACKET が上位でも、目標時間を満たしているクエリしかないなら対応は不要です。待機統計の順位を平準化すること自体は目的になりません。

  • 統計情報を更新する

    推定行数の乖離が原因で不要な並列プランが選ばれている場合、統計更新でプランが変わることがあります。並列度設定より先に確認すべき項目です。

  • 特定クエリだけ並列度を制限する

    問題のクエリが限定されているなら、`OPTION (MAXDOP n)` でそのクエリだけを制御します。サーバー全体への影響がありません。

事前検討が必要な変更

  • Cost Threshold for Parallelism を見直す

    小さいクエリまで並列化されていることが計測で確認できた場合に検討します。適正値はワークロードによって異なるため、変更前後の実行プランと応答時間を比較して決めます。

  • MAXDOP を見直す

    サーバー全体またはデータベース単位で並列度の上限を設定します。実行プランがサーバー全体で変わるため、段階的な適用と効果測定が前提です。

  • インデックスを設計し直す

    大規模スキャンが並列化されているケースでは、適切なインデックスの追加によって並列実行そのものが不要になります。

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

  • 待機統計をクリアして再計測する

    インスタンス全体の累計統計がリセットされ、他の監視ツールの基準も失われます。差分計測で代替できないか先に検討してください。

  • リソースガバナーで並列度を制御する

    専門家レビュー必須

    ワークロードグループ単位で並列度を制御できますが、設定を誤ると特定ワークロードが極端に遅くなります。エディション制約もあるため、設計レビューを前提とします。

!注意事項

  • CXPACKET が待機の上位にあることは、それ自体では問題の証拠になりません。「CXPACKET が多い=MAXDOP を1にする」という短絡的な対応は、並列実行で成立していた分析系処理を大きく遅くする可能性があります。
  • SQL Server 2016 SP2 / 2017 CU3 以降では、並列実行における無害な待機の一部が CXCONSUMER として分離されました。この版以降では CXCONSUMER を CXPACKET と同列に扱わないでください。
  • `sys.dm_os_wait_stats` はインスタンス起動時からの累計です。稼働時間の異なるインスタンス同士を絶対値で比較しても意味がありません。
  • `DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)` はインスタンス全体の統計をリセットします。同じインスタンスを参照する他の監視ツールにも影響します。
  • 並列度の設定変更はサーバー全体の実行プランに影響します。CXPACKET の数値を下げること自体を目的にしないでください。

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

SQL Server 2016 SP2 / 2017 CU3 以降並列実行の待機が CXPACKET と CXCONSUMER に分離されました。CXCONSUMER はコンシューマー側スレッドの待機を表し、一般に無害とされています。この版以降では両者を分けて評価してください。
SQL Server 2016 以降`sys.dm_exec_requests` に `dop` 列があり、リクエストごとの実際の並列度を確認できます。それ以前の版ではこの列を外して実行してください。
SQL Server 2012 以降`sys.dm_os_sys_info.sqlserver_start_time` でインスタンス起動時刻を取得できます。累計待機時間を評価する際の基準になります。
Amazon RDS for SQL Server待機統計のDMVはそのまま参照できます。MAXDOP や Cost Threshold の変更はDBパラメータグループ経由になるため、対応手順が異なります。

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

  • 実行プランのスレッドごとの行数分布

    実際の実行プランで、並列スレッド間の行数に大きな偏りが無いかを確認します。偏りがあればスキューです。

  • CPU 使用率とスケジューラの状態

    `sys.dm_os_schedulers` の `runnable_tasks_count` を確認し、CPU 待ち行列が積み上がっていないかを見ます。

  • PAGEIOLATCH 系の待機

    CXPACKET と併せて I/O 待機が上位なら、根本原因はストレージ側の可能性があります。

  • メモリ許可待ち(RESOURCE_SEMAPHORE)

    並列クエリはメモリ許可を多く要求します。この待機が併発している場合はメモリ側の検討も必要です。

この文書の根拠と限界

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

SQL Server の `sys.dm_os_wait_stats`、`sys.dm_os_waiting_tasks`、`sys.dm_exec_requests`、`sys.dm_os_sys_info` および `DBCC SQLPERF` の公開仕様に基づく一般的な確認手順です。CXCONSUMER の追加時期は SQL Server 2016 SP2 / 2017 CU3 として記載していますが、適用ビルドの詳細は対象環境のバージョン情報で確認してください。特定顧客の実測値は含みません。

よくある質問

CXPACKET待機が多いのは問題ですか?

待機の上位にあること自体は問題ではありません。CXPACKET は並列クエリが動いている証拠であり、分析系の処理が多い環境では上位に来るのが通常です。実際に目標時間を超えている処理があり、それが並列待機と結び付いている場合にはじめて対応対象になります。

CXPACKETとCXCONSUMERの違いは何ですか?

SQL Server 2016 SP2 / 2017 CU3 以降で、並列実行の待機のうちコンシューマー側スレッドの待機が CXCONSUMER として分離されました。CXCONSUMER は一般に無害とされており、CXPACKET と同列に扱うと過剰な対応につながります。

Productionで実行できますか?

参照用のSQLと差分計測はいずれも本番環境で実行できます。`DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)` はインスタンス全体の統計をリセットするため、本番では推奨しません。差分計測で代替してください。

AWS RDSでも使用できますか?

待機統計のDMV(`sys.dm_os_wait_stats`、`sys.dm_os_waiting_tasks`)は Amazon RDS for SQL Server でそのまま参照できます。ただし並列度の設定変更はDBパラメータグループ経由になるため、`sp_configure` を前提とした手順はそのままでは使えません。

どの権限が必要ですか?

参照用SQLには VIEW SERVER STATE が必要です。待機統計のクリアにはサーバーレベルの権限(sysadmin 相当)が必要で、マネージドサービスでは実行できない場合があります。

結果をどう判断しますか?

累計値の順位ではなく、問題が起きている時間帯の差分で評価してください。そのうえで、遅いクエリの実行プランに並列演算子があり、スレッド間の行数に偏りがある場合に並列度の見直しへ進みます。

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

  • CXPACKETが待機の上位に出るのは異常なのか知りたい
  • 待機事象の見方を知りたい
  • 並列クエリの待ちを実行中に確認したい

リスク表示の意味

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

GIIPの対応範囲

CXPACKET のような待機事象は、瞬間値ではなく「いつもと比べてどうか」で判断する指標です。GIIP では待機統計を定期的にスナップショットとして保持し、時間帯ごとの差分を比較できる形で蓄積しています。AIエージェントが平常時のパターンから外れた変化を検出し、実際に遅くなったクエリと結び付いたときだけ担当者に上げるため、「CXPACKET が上位だから並列度を下げる」といった数値先行の判断を避けられます。

執筆・技術検証

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

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

関連するナレッジ

関連サービス

待機事象の分析を依頼する

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

待機事象の分析を依頼する

ナレッジベース一覧へ