2016-10-08 4 views
1

複雑なクエリがSQL Server上で許容できないほどゆっくり(トランザクションあたり約10秒)実行されるという問題があります。 クエリでは、対応する変数に対して40個のフィールド(列)が一致し、すべてのフィールドが一致するか、フィールドと変数の両方がnullである行が返されます。 少なくとも最初のいくつかのフィールドがインデックスされます。 これは、クエリの最初のフィールドがほぼすべてのレコードで一致するためです。一致する可能性の低いフィールドが最初に配置されるように、クエリを並べ替えると、不一致が見つかった場合に特定の行のクエリを早期終了できますか? 他にどんなスピードアップがありますか?変数を再命名とSQLクエリーの速度にwhere句の順序の影響

クエリは、次のとおりです。

SELECT _pk FROM FinancialDetail 
WHERE (Field01 = @Field01 OR (Field01 IS NULL AND @Field01 IS NULL)) 
    AND (Field02 = @Field02 OR (Field02 IS NULL AND @Field02 IS NULL)) 
    AND (Field03 = @Field03 OR (Field03 IS NULL AND @Field03 IS NULL)) 
    AND (Field04 = @Field04 OR (Field04 IS NULL AND @Field04 IS NULL)) 
    AND (Field05 = @Field05 OR (Field05 IS NULL AND @Field05 IS NULL)) 
    AND (Field06 = @Field06 OR (Field06 IS NULL AND @Field06 IS NULL)) 
    AND (Field07 = @Field07 OR (Field07 IS NULL AND @Field07 IS NULL)) 
    AND (Field08 = @Field08 OR (Field08 IS NULL AND @Field08 IS NULL)) 
    AND (Field09 = @Field09 OR (Field09 IS NULL AND @Field09 IS NULL)) 
    AND (Field10 = @Field10 OR (Field10 IS NULL AND @Field10 IS NULL)) 
    AND (Field11 = @Field11 OR (Field11 IS NULL AND @Field11 IS NULL)) 
    AND (Field12 = @Field12 OR (Field12 IS NULL AND @Field12 IS NULL)) 
    AND (Field13 = @Field13 OR (Field13 IS NULL AND @Field13 IS NULL)) 
    AND (Field14 = @Field14 OR (Field14 IS NULL AND @Field14 IS NULL)) 
    AND (Field15 = @Field15 OR (Field15 IS NULL AND @Field15 IS NULL)) 
    AND (Field16 = @Field16 OR (Field16 IS NULL AND @Field16 IS NULL)) 
    AND (Field17 = @Field17 OR (Field17 IS NULL AND @Field17 IS NULL)) 
    AND (Field18 = @Field18 OR (Field18 IS NULL AND @Field18 IS NULL)) 
    AND (Field19 = @Field19 OR (Field19 IS NULL AND @Field19 IS NULL)) 
    AND (Field20 = @Field20 OR (Field20 IS NULL AND @Field20 IS NULL)) 
    AND (Field21 = @Field21 OR (Field21 IS NULL AND @Field21 IS NULL)) 
    AND (Field22 = @Field22 OR (Field22 IS NULL AND @Field22 IS NULL)) 
    AND (Field23 = @Field23 OR (Field23 IS NULL AND @Field23 IS NULL)) 
    AND (Field24 = @Field24 OR (Field24 IS NULL AND @Field24 IS NULL)) 
    AND (Field25 = @Field25 OR (Field25 IS NULL AND @Field25 IS NULL)) 
    AND (Field26 = @Field26 OR (Field26 IS NULL AND @Field26 IS NULL)) 
    AND (Field27 = @Field27 OR (Field27 IS NULL AND @Field27 IS NULL)) 
    AND (Field28 = @Field28 OR (Field28 IS NULL AND @Field28 IS NULL)) 
    AND (Field29 = @Field29 OR (Field29 IS NULL AND @Field29 IS NULL)) 
    AND (Field30 = @Field30 OR (Field30 IS NULL AND @Field30 IS NULL)) 
    AND (Field31 = @Field31 OR (Field31 IS NULL AND @Field31 IS NULL)) 
    AND (Field32 = @Field32 OR (Field32 IS NULL AND @Field32 IS NULL)) 
    AND (Field33 = @Field33 OR (Field33 IS NULL AND @Field33 IS NULL)) 
    AND (Field34 = @Field34 OR (Field34 IS NULL AND @Field34 IS NULL)) 
    AND (Field35 = @Field35 OR (Field35 IS NULL AND @Field35 IS NULL)) 
    AND (Field36 = @Field36 OR (Field36 IS NULL AND @Field36 IS NULL)) 
    AND (Field37 = @Field37 OR (Field37 IS NULL AND @Field37 IS NULL)) 
    AND (Field38 = @Field38 OR (Field38 IS NULL AND @Field38 IS NULL)) 
    AND (Field39 = @Field39 OR (Field39 IS NULL AND @Field39 IS NULL)) 
    AND (Field40 = @Field40 OR (Field40 IS NULL AND @Field40 IS NULL)) 
+0

私は、提供されたパラメータに基づいて手続き内で動的クエリを作成します。それは間違いなく実行をスピードアップします。 –

+1

私はあなたがhttp://www.sommarskog.se/dyn-search.htmlを熟読することをお勧めします。 SQL Serverのバージョンは重要で、SELECT @@ VERSION;で判断できます。 –

+0

私はクライアント(第3レベル)をサポートしており、クライアントシステムに直接アクセスすることはできませんので、私は(まだ)DBバージョンを知っていません。表の回りは5〜800万行です。 –

答えて

3

これは動的検索ではありません。すべての列が比較されています。セマンティクスを変更せずに削除することはできません。

Field01 = @Field01 OR (Field01 IS NULL AND @Field01 IS NULL) 

2つのNullが等しいと見なされる場合、両方が等しいことを意味します。このパターンでは、通常、SQL Serverに問題は発生しません。伐採の例では、インデックスは、この計画が実際に

SELECT _pk FROM #FinancialDetail 
WHERE (Field01 = @Field01) 
    AND (Field02 = @Field02) 
    AND (Field03 = @Field03) 

のための1と区別できない3つのすべての列

enter image description here

に求めて示し

CREATE TABLE #FinancialDetail 
(
_pk INT PRIMARY KEY, 
Field01 INT, 
Field02 INT, 
Field03 INT 
) 
CREATE INDEX IX ON #FinancialDetail(Field01, Field02, Field03) 

declare @Field01 int, @Field02 int, @Field03 int; 

SELECT _pk FROM #FinancialDetail 
WHERE (Field01 = @Field01 OR (Field01 IS NULL AND @Field01 IS NULL)) 
    AND (Field02 = @Field02 OR (Field02 IS NULL AND @Field02 IS NULL)) 
    AND (Field03 = @Field03 OR (Field03 IS NULL AND @Field03 IS NULL)) 

ですインデックス内の等価演算子が異なるセマンティクスを使用しているという事実NULLは私たちに公開されていませんas discussed in the comments here

非常に選択的な列の組み合わせでは複合インデックスが必要です(SQL Serverでは最大16個のキー列が使用できます)。その上でシークを得ることができるはずです。

既存の単一列インデックスを使用する必要があり、最適なインデックスが異なる場合は、OPTION (RECOMPILE)を追加できます。

また、以下のように、より短く同じセマンティクスを書き直すこともできますが、私はそれが計画に何か変わることはないと考えています。

SELECT _pk FROM #FinancialDetail 
WHERE EXISTS (SELECT @Field01, @Field02, @Field03 /*.... , @Field40*/ 
       INTERSECT 
       SELECT Field01, Field02, Field03 /*.... , Field40*/) 
+0

オプション(再コンパイル)ヒントを使用することは、私が必要とする解決策であることが判明しました。動的SQLを使用しても問題は解決していますが、アプリケーション構造によって実装が難しくなっている可能性があります。 –

1

をこのコメントのために少し長いです。私は、ORの条件がオプティマイザを混乱させていると推測しています。あなたは複雑な(繰り返していますが)WHEREという状態です。

大きな問題の1つは、SQL Serverが実行計画をキャッシュすることです。最初にクエリを実行すると、計画が設定されます。後で値を使用すると、索引をうまく利用できるようになるため、必ずしも使用されるとは限りません。

ORの条件を削除するには、動的SQLをお勧めします。結果の条件は変数の値に依存します。 @Field02@Field03NULLた場合、その条件は次のようになります。

WHERE (Field01 = @Field01) AND 
     (Field02 IS NULL) AND 
     (Field03 IS NULL) AND 
     (Field04 = @Field04) AND 
     . . . 

これらは、処理するためのオプティマイザのためにはるかに簡単であるべき、平等に厳密にAND条件です。

関連する問題