2012-05-18 3 views
6

同じクエリを2回使用する必要がありますが、where句が少し異なります。私は、ビット値で同じストアドプロシージャを呼び出すだけで、IF ... ELSE ...ステートメントを持って、比較するフィールドを決定するのが効率的かどうか疑問に思っていました。Sql Serverはストアドプロシージャのロジックフローの実行計画をどのようにコンパイルしますか?

私は2つのストアドプロシージャを作成し、それぞれのロジックをアプリケーションに基づいて呼び出す必要がありますか?

適切に理解するために、これについてさらに詳しく知りたいと思います。 このために実行計画はどのようにコンパイルされていますか?それぞれのコードブロックに1つずつありますか?ELSE ...?

それとも大きな実行計画としてまとめられていますか?

+0

詳しい情報... .'(または 'CASE')には正確に?場合によっては、条件をパラメータに抽象化することが可能であり、より効率的です。 procごとに1つの実行計画があるため、条件付きロジックによって不均一なパフォーマンスが生じる可能性があります。 –

答えて

1

プロシージャに渡されるパラメータの初期値を使用して1回コンパイルされます。いくつかのステートメントは遅延コンパイルの対象となるかもしれませんが、最終的にコンパイルされたときにパラメータ値が何であれコンパイルされます。

これは、以下を実行して実際の実行計画を見て見ることができます。そのステートメントが1のに渡された初期パラメータ値に応じてコンパイルされたため2ケースの実行

CREATE TABLE T 
    (
    C INT 
) 

INSERT INTO T 
SELECT 1 AS C 
UNION ALL 
SELECT TOP (1000) 2 
FROM master..spt_values 
UNION ALL 
SELECT TOP (1000) 3 
FROM master..spt_values 

GO 

CREATE PROC P @C INT 
AS 
    IF @C = 1 
     BEGIN 
      SELECT '1' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 2 
     BEGIN 
      SELECT '2' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 3 
     BEGIN 
      CREATE TABLE #T 
      (
       X INT 
      ) 

      INSERT INTO #T 
      VALUES  (1) 

      SELECT '3' 
      FROM T, 
       #T 
      WHERE C = @C 
     END 

GO 

EXEC P 1 

EXEC P 2 

EXEC P 3 

DROP PROC P 

DROP TABLE T 

1としてTからの行の推定数ない1000を示しています。 3ケースを実行すると、(まだ作成されていない)一時テーブルへの参照が遅延コンパイルの対象であったことを意味するので、正確な推定カウントは1000となります。

3

キャッシュされている実行計画について心配するのは当然です。

マーティンは、計画がキャッシュされ、最初に実行されたときにロジックの特定のブランチに対して最適化されることを示す良い例を示しています。 異なるパラメータでストアドプロシージャ(sproc)を呼び出しても、最初の実行後にそのプランが再利用され、実行フローが別のブランチを選択します。 これは非常に悪く、パフォーマンスを低下させます。私はこれが何度も起こるのを見ており、根本的な原因を見つけるのにしばらく時間がかかります。

「パラメータスニッフィング」と呼ばれており、調査する価値があります。

私がアドバイスしていない共通の解決策は、あなたのsprocをいくつかの小さなものに分割することです。 sprocの内部でsprocを呼び出すと、内部のsprocはそれに渡されるパラメータに最適化された実行計画を取得します。

sprocをいくつかの小さなものに分割するのは、正当な理由がない場合(良い理由はモジュール性です)は醜い回避策です。 Martinは、スキーマに変更を導入することによってステートメントを再コンパイルすることが可能であることを示しています。 私は、ステートメントの最後にOPTION(RECOMPILE)を使用します。これは、現在の値すべての変数を考慮して、ステートメントの再コンパイルを実行するようオプティマイザに指示します。パラメータだけでなく、ローカル変数も考慮され、良い計画と悪い計画の違いがあります。

パラメータに応じて別のwhere句を使用してクエリを作成することに戻ってください。下側があれば影響を与えることができた(それはしかし声明の時点までキャッシングは影響しません。)この文の実行計画がキャッシュされないことである

WHERE 
(@parameter1 is null or col1 = @parameter1 ) 
AND 
(@parameter2 is null or col2 = @parameter2 ) 
... 
OPTION (RECOMPILE) 

:私は、次のパターンを使用しますコンパイル時間が考慮されるべきであるので、sprocは何度も実行される。プロダクション品質のデータを使ってテストを実行すると、問題がある場合に回答が得られます。

読み取り可能でエレガントなsprocsをコード化でき、不適切な足にオプティマイザを設定できないという点があります。

さらに注意する必要があるもう1つの選択肢は、sprocレベル(ステートメントレベルとは対照的に)レベルがそれほど細かくなく、さらに重要なことに、ローカル変数の値を考慮しないで、最適化するとき。 http://www.sommarskog.se/dyn-search-2005.html http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/何だろう `IF ... ELSE

+0

なぜアップフォースはありませんか?正当な答え。 –