9

列のインデックスがオプティマイザーによって使用されるように、次のクエリを書き直す賢明な方法があるのだろうか?

CREATE PROCEDURE select_Proc1
    @Key1 int=0,
    @Key2 int=0
AS
BEGIN
    SELECT key3
    FROM Or_Table
    WHERE (@key1 = 0 OR Key1 = @Key1) AND
          (@key2 = 0 OR Key2 = @Key2)
END
GO

この記事によると、PreethivirajKulasinghamによるパラメータで使用される場合の「OR」句の使用を最適化する方法:

句の列はWHEREインデックスでカバーされていますが、SQLServerはこれらのインデックスを使用できません。これは、インデックスの使用を「ブロック」しているものがあるかどうかという疑問を提起します。この質問に対する答えは「はい」です。原因はパラメータとOR条件です。

パラメータはインデックスでカバーされていません。つまり、SQL Serverはどのインデックスも評価に使用できません@key1=0(この条件はにも適用されます@key2=0)。

事実上、これはSQL Serverがインデックスを使用して句を評価できないことを意味します@key1=0 OR Key1= @key1OR句は両方の条件でカバーされる行の結合であるため)。同じ原則が他の節(re。key2)にも当てはまります。これにより、SQL Serverは、行を抽出するためにインデックスを使用できないと結論付け、SQLServerは次善のアプローチであるクラスター化インデックススキャンを利用することになります。

ご覧のとおり、句で述語がOR編集されている場合、SQLオプティマイザは列のインデックスを使用しません。WHEREこの問題の1つの解決策はIF、パラメーターのすべての可能な組み合わせに対して句を使用してクエリを分離することです。

さて、私の質問は、可能な組み合わせが3つか4つ以上の場合、どうすればよいでしょうか。組み合わせごとに個別のクエリを作成することは、合理的な解決策とは思えません。

この問題に対する他の回避策はありますか?

4

4 に答える 4

12

SQL ServerOR述語の最適化にはあまり適していません。

これを使って:

SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 = 0
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 <> 0
        AND key2 = @key2
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key2 = 0
        AND @key1 <> 0
        AND key1 = @key1
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 <> 0
        AND @key2 <> 0
        AND key1 = @key1
        AND key2 = @key2

SQL Serverクエリを実行する前に変数の値を調べ、冗長なクエリを最適化します。

これは、4つのクエリのうち1つだけが実際に実行されることを意味します。

于 2010-01-29T11:40:29.260 に答える
5

MSSQL 2008には、条件の簡略化の最適化構文があります。

 Where (@key1 =0 OR Key1 =@Key1) AND
      (@key2 =0 OR Key2 =@Key2) option(recompile)

これにより、定数の使用が最適化されます

于 2010-01-29T11:52:15.497 に答える
2

はい-動的SQLを注意深く使用すると、この問題が解決します。それを行うには2つの方法があります。

  1. ストアドプロシージャに関する「純粋主義者」の場合は、ストアドプロシージャ内にカスタムクエリ文字列を作成し、その文字列を実行します。次に、特定のクエリを実行ごとに動的に記述して、関連する基準のみを含めることができます。

  2. このSQLの場所に柔軟性がある場合は、(ここでも注意深く)アプリケーションでクエリ文字列を作成してサーバーに渡すことができます。

    もちろん、危険はSQLインジェクションの周りにあります。したがって、データがクライアントから動的SQLステートメントに渡される方法には十分注意する必要があります。

Erland Sommarskogからの本当に徹底的で包括的な記事

于 2010-01-30T00:35:12.280 に答える
2

テーブル値関数を試しましたか?

CREATE FUNCTION select_func1 (  
    @Key1 int=0,
    @Key2 int=0
)
RETURNS TABLE 
AS RETURN (
    Select key3
    From Or_Table
    Where (@key1 =0 OR Key1 =@Key1) AND
          (@key2 =0 OR Key2 =@Key2)
)


select * from select_func1(1,2)
于 2010-01-29T12:48:10.310 に答える