実行プランの品質は、各プランオペレーターによって出力される推定行数の精度に大きく依存します。推定行数が実際の行数から大幅に偏っている場合、これはクエリの実行プランの品質に大きな影響を与える可能性があります。計画の質が悪いと、過剰なI / O、CPUの膨張、メモリの負荷、スループットの低下、全体的な同時実行性の低下の原因となる可能性があります。
「プランの品質」とは、SQL Serverに実行プランを生成させ、データの現在の状態を反映する物理的なオペレーターの選択をもたらすことです。正確なデータに基づいてこのような決定を行うことにより、クエリが適切に実行される可能性が高くなります。カーディナリティの見積もり値は、オペレーターの原価計算の入力として使用され、値が現実から離れすぎている場合は、実行計画への悪影響が顕著になる可能性があります。これらの見積もりは、クエリ自体に関連付けられたさまざまなコストモデルに送られます。不正な行の見積もりは、インデックスの選択、シークとスキャンの操作、並列とシリアルの実行、結合アルゴリズムの選択、内部と外部の物理的な結合など、さまざまな決定に影響を与える可能性があります。選択(ビルドとプローブなど)、スプールの生成、ブックマークの検索と完全なクラスター化またはヒープテーブルへのアクセス、ストリームまたはハッシュの集計の選択、データの変更でワイドプランとナロープランのどちらを使用するか。
例として、次のSELECT
があるとします。 クエリ(クレジットデータベースを使用):
SELECT m.member_no, m.lastname, p.payment_no, p.payment_dt, p.payment_amt FROM dbo.member AS m INNER JOIN dbo.payment AS p ON m.member_no = p.member_no;
クエリロジックに基づいて、次の計画はあなたが期待するものを形作っていますか?
そして、ネストされたループの代わりにハッシュマッチがあるこの代替プランはどうですか?
「正しい」答えは、他のいくつかの要因に依存しますが、主要な要因の1つは、各テーブルの行数です。場合によっては、一方の物理的結合アルゴリズムが他方よりも適切であり、最初のカーディナリティ推定の仮定が正しくない場合、クエリは最適でないアプローチを使用している可能性があります。
識別 カーディナリティ推定の問題は比較的簡単です。実際の実行プランがある場合は、演算子の推定行数と実際の行数の値を比較して、スキューを探すことができます。 SQL Sentry Plan Explorerは、グラフィカルプランの個々のオペレーターにカーソルを合わせるのではなく、単一のプランツリータブですべてのオペレーターの実際の行と推定行を表示できるようにすることで、このタスクを簡素化します。
現在、スキューによってプランの品質が低下するとは限りませんが、クエリでパフォーマンスの問題が発生し、プランにそのようなスキューが見られる場合は、これをさらに調査する価値のある領域の1つです。
カーディナリティ推定の問題の特定は比較的簡単ですが、解決策はそうではないことがよくあります。カーディナリティ推定の問題が発生する理由にはいくつかの根本的な原因があります。この投稿では、より一般的な10の理由について説明します。
統計の欠落または失効
カーディナリティ推定の問題のすべての理由の中で、これはあなたが望んでいる理由です。 対処するのが最も簡単なことが多いので、見てください。このシナリオでは、統計が欠落しているか、古くなっています。自動統計の作成と更新のデータベースオプションを無効にしたり、特定の統計に対して「再計算なし」を有効にしたり、自動統計の更新が十分に頻繁に行われないほど十分な大きさのテーブルがある場合があります。
サンプリングの問題
統計ヒストグラムの精度が不十分である可能性があります。たとえば、データの偏りが大きい、または頻繁にある非常に大きなテーブルがある場合などです。サンプリングをデフォルトから変更する必要がある場合があります。それでも問題が解決しない場合は、個別のテーブル、フィルター処理された統計、またはフィルター処理されたインデックスを使用して調査してください。
非表示の列の相関
クエリオプティマイザは、同じテーブル内の列が独立していることを前提としています。たとえば、市と州の列がある場合、これら2つの列が相関していることが直感的にわかる場合がありますが、SQL Serverは、関連付けられた複数列のインデックスまたは手動で作成された複数列のインデックスを使用しない限り、これを理解しません。列の統計。オプティマイザーの相関関係を支援しないと、述語の選択性が誇張される可能性があります。
以下は、2つの相関する述語の例です。
SELECT lastname, firstname FROM dbo.member WHERE city = 'Minneapolis' AND state_prov - 'MN';
10,000行のmember
の10%がたまたま知っています テーブルはこの組み合わせの対象となりますが、クエリオプティマイザは10,000行の1%であると推測しています:
ここで、これを、複数列の統計を追加した後に表示される適切な見積もりと比較してください。
テーブル内の列の比較
同じテーブル内の列を比較すると、カーディナリティ推定の問題が発生する可能性があります。これは既知の問題です。そうする必要がある場合は、代わりに計算列を使用するか、自己結合または共通テーブル式を使用するようにクエリを書き直すことで、列比較のカーディナリティ推定を改善できます。
テーブル変数の使用法
テーブル変数を多用しますか?テーブル変数は、カーディナリティの推定値「1」を示しています。これは、少数の行では問題にならない可能性がありますが、結果セットが大きい場合や不安定な場合は、クエリプランの品質に大きな影響を与える可能性があります。以下は、@charge
からの実際の1,600,000行に対する1行のオペレーターの見積もりのスクリーンショットです。 テーブル変数:
これが根本的な原因である場合は、可能な場合は一時テーブルや永続的なステージングテーブルなどの代替手段を検討することをお勧めします。
スカラーおよびMSTVUDF
テーブル変数と同様に、マルチステートメントのテーブル値関数とスカラー関数は、カーディナリティ推定の観点からはブラックボックスです。それらが原因でプランの品質の問題が発生した場合は、代わりにインラインテーブル関数を検討してください。または、関数参照を完全に引き出して、オブジェクトを直接参照することもできます。
以下は、マルチステートメントのテーブル値関数を使用した場合の推定計画と実際の計画を示しています。
データ型の問題
検索および結合条件に関連する暗黙的なデータ型の問題は、カーディナリティ推定の問題を引き起こす可能性があります。また、サーバーレベルのリソース(CPU、I / O、メモリ)を密かに食い尽くす可能性もあるため、可能な限りそれらに対処することが重要です。
複雑な述語
このパターンは以前に見たことがあると思います– WHERE
を使用したクエリ さまざまな関数、連結演算、数学演算などでラップされた各テーブル列参照を持つ句。また、すべての関数のラッピングが適切なカーディナリティの推定を妨げるわけではありませんが(LOWER
など) 、UPPER
およびGETDATE
)クエリオプティマイザが正確な推定を実行できなくなるまで述語を埋める方法はたくさんあります。
クエリの複雑さ
埋め込まれた述語と同様に、クエリは非常に複雑ですか? 「複雑」は主観的な用語であり、評価は異なる場合がありますが、重複するテーブルを参照するビュー内のビュー内にビューをネストすることは、特に10以上のテーブル結合、関数参照と組み合わせると、最適ではない可能性が高いことにほとんどの人が同意できます。と埋もれた述語。クエリオプティマイザは素晴らしい仕事をしますが、それは魔法ではありません。かなりの偏りがある場合、クエリの複雑さ(スイスアーミーナイフクエリ)により、演算子の正確な行推定を導き出すことがほぼ不可能になる可能性があります。
分散クエリ
リンクサーバーで分散クエリを使用していて、カーディナリティの見積もりに重大な問題がありますか?その場合は、データへのアクセスに使用されているリンクサーバープリンシパルに関連付けられている権限を必ず確認してください。最小のdb_ddladmin
なし リンクサーバーアカウントのデータベースの役割が固定されています。権限が不十分なためにリモート統計が表示されないことが、カーディナリティ推定の問題の原因である可能性があります。
そして他にもあります…
カーディナリティの推定値が歪む可能性がある理由は他にもありますが、最も一般的なものについては説明したと思います。重要な点は、既知のパフォーマンスの低いクエリに関連するスキューに注意を払うことです。計画が正確な行数条件に基づいて生成されたと想定しないでください。これらの数値が歪んでいる場合は、最初にこれをトラブルシューティングする必要があります。