web-dev-qa-db-ja.com

実行プランでのオペレーターの位置付けのソート

パフォーマンスの問題をトラブルシューティングし、レポートクエリの安定した実行計画を取得しようとしています。実際の計画へのリンクは以下のとおりです。

良い vs 悪い

Goodプランを見ると、並べ替えはテーブルの結合後です。悪い計画の場合、ソートは最後の結合の直前です。並べ替えが最後の結合の前であり、並べ替えの推定行数が5000であるため、計画が適切でない場合、SQL Serverはネストされたループ結合を使用することを決定し、クエリが遅くなります。

テーブル結合ヒントを使用したくない、またはTOPの変数を変更したくない。

このシナリオで一貫した計画を得るために使用できる戦略は何ですか?

このクエリは約5分ごとに実行されます。

5
jesijesi

古典的なパラメータスニッフィングの問題があるようです。私の知る限り、あなたのクエリは同じですが、どちらも異なるキャッシュプランを使用しています。取得されるキャッシュされたプランは、最初の実行の入力パラメーターによって異なります。すべての入力に対して十分に機能する計画があり、その計画が必要だと思います。ただし、パラメーター値によっては、運が悪くなり、一部の入力ではうまく機能するが、他の入力ではうまく機能しない計画になる可能性があります。

可能であれば、RECOMPILEヒントをクエリに追加します。これにより、クエリオプティマイザーはクエリにキャッシュされたプランを使用できなくなりますが、プランを作成するときに変数の値が表示されます。一般的な経験則として、オプティマイザにより多くの情報を提供できれば、パフォーマンスが向上します。このアプローチの欠点は、クエリプランが毎回再コンパイルされることですが、これは3つのテーブルクエリにすぎません。クエリが1秒あたり数百回実行されない限り、心配する必要はありません。

別のオプションは、_OPTIMIZE FOR_ query hint を使用することです。これにより、入力値に基づいていないキャッシュされたプランが提供されるため、キーは、可能なすべての入力値に対して十分に機能するクエリプランを取得することです。 その他の質問 では、TOPのデフォルトの100行の推測に満足していないため、クエリオプティマイザーで特定のTOP値を次のように強制的に最適化できます。

_OPTION (OPTIMIZE FOR UNKNOWN, OPTIMIZE FOR (@top = 5000));
_

入力変数は、プランを形成するために傍受されません。その構文は奇妙に見えるかもしれませんが、許可されています:

OPTIMIZE FOR @variable_name = literal_constantとOPTIMIZE FOR UNKNOWNが同じクエリヒントで使用されている場合、クエリオプティマイザーは特定の値に指定されたliteral_constantを使用し、残りの変数値にはUNKNOWNを使用します。値はクエリの最適化中にのみ使用され、クエリの実行中には使用されません。

これらのオプションのいずれも機能せず、適切に機能するクエリプランがあると確信できる場合は、プランガイドを使用して調べることができます。

3
Joe Obbish