web-dev-qa-db-ja.com

値が常に同じになる場合、リテラル値またはパラメーター値を使用する述語に違いはありますか?

常にステータスでフィルタリングするクエリがありますが、これらの方法のいずれかが他よりもパフォーマンス上の利点はありますか?

(これはアドホッククエリのコンテキストにあります。UserStatusのデータ型はintです)

...
AND UserStatus = 1
...

または

DECLARE @userStatus int = 1
...
AND UserStatus = @userStatus
...

(p.s.値が不明/変化している場合のパラメータとリテラルの違いについては話さないでください。これは別のトピックです)

7
JeremyWeir

別に指定されていないため、SSMSのクエリから実行されているローカル変数について話していると想定してください。リテラルAND UserStatus = @userStatusで使用するのと同じ値をAND UserStatus = 1に使用しても、カーディナリティの推定値が生成される方法により、実行プランに違いが見られます。

リテラル値を使用すると、SQL Serverはそのテーブルの histogram に移動し、その値が範囲キー内のどこに収まるかを確認します。その上で収集された見積もりは、2つのシナリオのいずれかになります。

HISTOGRAM DIRECT HIT基本的に、これは、クエリ内の特定のリテラル値にRANGE_HI_KEY(ヒストグラムの任意のステップの上位列の値)値があるため、見積もりは、ヒストグラムのEQ_ROWS(値がRANGE_HI_KEYと等しい行の数)の数と一致します。つまり、推定値は、統計を最後に更新したときの値に一致する行数になります。

HISTOGRAM INTRA-STEP HITこれは、2つのRANGE_HI_KEY値の間の範囲に値が存在する場合です。リテラル値がその範囲内にある場合、RANGE_ROWS(2つのヒストグラムステップ間の行数)、DINSTINCT_RANGE(ヒストグラムステップ内の個別の値の数)、およびAVG_RANGE_ROWSRANGE_ROWS/DISTINCT_RANGE_ROWS)によって計算され、見積もり。

ただし、ローカル変数を使用して実行する場合、@Variableは実行時に不明であるため、これらの値のヒストグラムに移動することはありません。

このトピックの詳細については、このホワイトペーパー Joe Sack。 を読むことをお勧めします。

DENSITY VECTOR特定の値がない場合、SQLサーバーは代わりに密度を使用して、その述語に対して返される推定行数を決定できます。 。密度は1 /その列内の個別の値の数です。したがって、カーディナリティの見積もりは、密度*テーブルの行数になります。

とても長い話です。同じ値をローカル変数で何度も実行しても、リンクEricが Kendra Little から提供しているリンクでさらに説明されている理由により、同じ結果は得られません。

11
Zane

リテラル値はオプティマイザに認識されています(その値に基づいて選択性を推定できます)。

パラメータ値(ストアドプロシージャ、関数)は、実行時に傍受されます。後続の実行には、以前にコンパイルされた計画が最適でない可能性がある他の値が含まれる場合があります。

変数の場合、値はオプティマイザに認識されていません。それは密度を見ることができるかもしれません(on average我々は特定の値に対してこれだけ多くの行を持っています)、またはハードワイヤード推定を使用します(たとえば>> 10%の選択性をもたらすなど)ワードに接続されたパーセンテージはそうかもしれません)。

7
Tibor Karaszi