昨年のいくつかの投稿では、人々が特定の待機タイプを見て、そこにいる待機に対して「ひざまずく」方法で反応するというテーマを使用しました。通常、これは、インターネットに関する不十分なアドバイスに従い、抜本的で不適切な行動を取るか、問題の根本原因について結論を導き出し、その後、野蛮な追跡に時間と労力を浪費することを意味します。
ひざまずく反応が最も強く、最も悪いアドバイスがいくつか存在する待機タイプの1つは、CXPACKET待機です。これは、最も一般的に人のサーバーで最も多く待機する待機タイプでもあるため(2010年と2014年の2つの大きな待機タイプの調査によると、詳細はこちらを参照)、この投稿で取り上げます。
>CXPACKET待機タイプとはどういう意味ですか?
最も簡単な説明は、CXPACKETはクエリが並列で実行されていることを意味し、CXPACKETが並列クエリを待機していることを*常に*確認できるということです。 CXPACKETの待機は、並列処理に問題があることを意味するものではありません。それを判断するには、さらに深く掘り下げる必要があります。
並列演算子の例として、グラフィカルクエリプランに次のアイコンがあるRepartitionStreams演算子について考えてみます。
これは、並列度(DOP)が4に等しい、この演算子の並列スレッドに関して何が起こっているかを示す図です。
DOP =4の場合、4つのプロデューサースレッドがあり、クエリプランの前半からデータを取得し、データは4つのコンシューマースレッドを介してクエリプランの残りの部分に戻されます。
sys.dm_os_waiting_tasks を使用して、リソースを待機している並列オペレーターのさまざまなスレッドを確認できます。 DMV、 exec_context_id 列(この投稿には、これを行うためのスクリプトがあります)。
並列プランには常に「制御」スレッドがあります。これは、歴史的な偶然によって常にスレッドID 0です。制御スレッドは常にCXPACKET待機を登録し、その期間はプランの実行にかかる時間と同じです。 Paul Whiteは、ここで並行計画のスレッドについて優れた説明をしています。
非制御スレッドがCXPACKET待機を登録するのは、オペレーターの他のスレッドの前に完了する場合のみです。これは、スレッドの1つがリソースを長時間待機している場合に発生する可能性があるため、(上記のスクリプトを使用して)CXPACKETが表示されないスレッドの待機タイプを確認し、適切にトラブルシューティングします。これは、スレッド間の作業分散が偏っている場合にも発生する可能性があります。この場合については、次の投稿で詳しく説明します(これは、古い統計やその他のカーディナリティ推定の問題が原因です)。
SQL Server2016SP2およびSQLServer2017 RTM CU3では、コンシューマースレッドはCXPACKET待機を登録しなくなったことに注意してください。それらはCXCONSUMER待機を登録しますが、これは無害であり、無視できます。これは、生成されるCXPACKET待機の数を減らすためであり、残りの待機は実行可能である可能性が高くなります。
予期しない並列処理?
CXPACKETは単に並列処理が発生していることを意味するため、最初に確認するのは、それを使用しているクエリに並列処理を期待するかどうかです。私のクエリは、並列処理が行われているクエリプランノードIDを提供します(スレッドの待機タイプがCXPACKETの場合、XMLクエリプランからノードIDを引き出します)。そのノードIDを探して、並列処理が意味をなすかどうかを判断します。 。
予期しない並列処理の一般的なケースの1つは、より小さなインデックスシークまたはスキャンが予想される場所でテーブルスキャンが発生する場合です。これはクエリプランに表示されるか、CXPACKET待機(注意すべき従来の待機統計パターン)とともに、多くのPAGEIOLATCH_SH待機(ここで詳細に説明)が表示されます。予期しないテーブルスキャンには、次のようなさまざまな原因があります。
- 非クラスター化インデックスがないため、テーブルスキャンが唯一の代替手段です
- 統計が古くなっているため、クエリオプティマイザはテーブルスキャンが使用するのに最適なデータアクセス方法であると判断します
- テーブルの列と変数またはパラメータのデータ型が一致しないため、暗黙的な変換。これは、非クラスター化インデックスを使用できないことを意味します。
- 変数またはパラメーターの代わりにテーブル列で算術演算が実行されているため、非クラスター化インデックスは使用できません
これらすべての場合において、解決策は、根本的な原因が何であるかによって決まります。
しかし、明らかな根本的なケースがなく、クエリが並行計画を正当化するのに十分な費用がかかると見なされた場合はどうなりますか?
並列処理の防止
特に、クエリオプティマイザーは、シリアルプランのコストがcost threshold for parallelism
よりも高い場合、並列クエリプランを作成することを決定します。 、インスタンスのsp_configure設定。並列処理(またはCTFP)のコストしきい値はデフォルトで5に設定されています。これは、並列プランの作成をトリガーするためにプランがそれほど高価である必要がないことを意味します。
不要な並列処理を防ぐ最も簡単な方法の1つは、CTFPをはるかに高い数に増やすことです。設定を大きくすると、並列計画が作成される可能性が低くなります。 CTFPを25〜50の範囲に設定することを推奨する人もいますが、すべての調整可能な設定と同様に、さまざまな値をテストして、環境に最適な値を確認することをお勧めします。適切なCTFP値を選択するのに役立つもう少しプログラム的な方法が必要な場合は、ジョナサンがブログ投稿を作成して、プランキャッシュを分析し、CTFPの推奨値を生成するためのクエリを示しています。例として、CTFPが200に設定されているクライアントと、並列処理を強制的に防止する方法として最大値(32767)に設定されているクライアントがあります。
サーバーの「最大並列度」(またはMAXDOP)を1に設定するだけでよいと思うのに、なぜ2番目のクライアントが並列処理を防ぐための大ハンマーの方法としてCTFPを使用しなければならなかったのか不思議に思うかもしれません。クエリMAXDOPヒントを指定し、サーバーのMAXDOP設定をオーバーライドしますが、CTFPをオーバーライドすることはできません。
これは、並列処理を制限するもう1つの方法です。並列処理したくないクエリに、MAXDOPヒントを設定します。
サーバーのMAXDOP設定を下げることもできますが、すべてが並列処理を使用できなくなる可能性があるため、これは抜本的な解決策です。最近では、サーバーのワークロードが混在しているのが一般的です。たとえば、一部のOLTPクエリと一部のレポートクエリがあります。サーバーのMAXDOPを下げると、レポートクエリのパフォーマンスが低下します。
ワークロードが混在している場合のより良い解決策は、上記のようにCTFPを使用するか、Resource Governor(エンタープライズのみです)を利用することです。 Resource Governorを使用してワークロードをワークロードグループに分割し、ワークロードグループごとにMAX_DOP(アンダースコアはタイプミスではありません)を設定できます。また、Resource Governorを使用することの良い点は、MAX_DOPをMAXDOPクエリヒントで上書きできないことです。
概要
CXPACKETが自動的に待機するという罠に陥らないでください。これは、並列処理がうまくいかないことを意味します。また、MAXDOPを1に設定してサーバーを非難することについて、私が見たインターネットのアドバイスに従わないでください。時間をかけてください。 CXPACKETが待機している理由と、それが対処すべきものなのか、正しく実行されているワークロードのアーティファクトなのかを調査します。
一般的な待機統計に関する限り、パフォーマンスのトラブルシューティングにそれらを使用する方法の詳細については、次のURLを参照してください。
- 待機統計から始まる私のSQLskillsブログ投稿シリーズ、またはどこが痛いのか教えてください
- 待機タイプとラッチクラスのライブラリはこちら
- 私のPluralsightオンライントレーニングコースSQLServer:待機統計を使用したパフォーマンスのトラブルシューティング
- SQL Sentry Performance Advisor
シリーズの次の記事では、歪んだ並列処理について説明し、それが発生していることを確認する簡単な方法を示します。それまでは、トラブルシューティングを行ってください。