1

興味深い問題が発生しました (少なくとも私にとっては興味深いことです)。以下は、私のクエリがどのように見えるかの一般的な考えです。@AuthorType がストアド プロシージャへの入力であり、コメントを入れた場所ごとにさまざまな特殊な条件があるとします。

SELECT *
FROM TBooks
WHERE
(--...SOME CONDITIONS)
OR
(@AuthorType = 1 AND --...DIFFERENT CONDITIONS)
OR
(@AuthorType = 2 AND --...STILL MORE CONDITIONS)

私にとって興味深いのは、@AuthorType = 0 でこの SP を実行すると、最後の 2 つの条件セット (@AuthorType の特殊な値の条件を追加するもの) を削除した場合よりも実行速度が遅くなることです。

SQL Server は、これらの条件が決して満たされないことを実行時に認識し、それらを完全に無視するべきではありませんか? 私が経験している違いは小さくありません。クエリの長​​さが約 2 倍になります (1 ~ 2 秒から 3 ~ 5 秒)。

SQL Server がこれを最適化しすぎることを期待していますか? 特別な条件のために、本当に 3 つの個別の SP が必要ですか?

4

3 に答える 3

6

SQL Server は、これらの条件が決して満たされないことを実行時に認識し、それらを完全に無視するべきではありませんか?

いいえ、絶対に違います。ここには 2 つの要因があります。

  1. SQL Server は、ブール演算子のショート サーキットを保証しません。クエリの最適化がブール式の評価の順序を逆にする方法を明確に示す例については、 「 On SQL Server ブール演算子の短絡」を参照してください。第一印象では、これは命令型の C ライクなプログラミング マインドセットにとってはバグのように思えますが、SQL の宣言型セット指向の世界では正しいことです。

  2. OR は SQL SARGability の敵です。SQL ステートメントは実行計画にコンパイルされ、計画が実行されます。プランは呼び出し間で再利用されます (キャッシュされます)。そのため、SQL コンパイラは、すべての個別の OR ケース (@AuthorType=1 AND @AuthorType=2 AND @AuthorType=3) に適合する単一のプランを生成する必要があります。クエリ プランの生成に関しては、ある意味で @AuthorType がすべての値を一度に持つ場合とまったく同じです。結果はほとんどの場合、考えられる最悪の計画であり、さまざまな OR 分岐が互いに矛盾するため、どのインデックスにも利益をもたらすことができず、最終的にテーブル全体をスキャンし、行を 1 つずつチェックすることになります。

あなたの場合、およびブール値 OR を含むその他の場合に行う最善の方法は、 @AuthorType をクエリの外に移動することです。

IF (@AuthorType = 1)
  SELECT ... FROM ... WHERE ...
ELSE IF (@AuthorType = 2)
  SELECT ... FROM ... WHERE ...
ELSE ...

各ブランチは明確に独自のステートメントに分離されているため、SQL は個々のケースごとに適切なアクセス パスを作成できます。

次善の策は、UNION ALL を使用することです。これは chadhoc が既に提案した方法であり、単一のステートメントが必要なビューやその他の場所での正しいアプローチです (IF は許可されません)。

于 2009-11-10T17:27:23.360 に答える
4

これは、オプティマイザーが「OR」タイプのロジックを処理するのがいかに難しいか、およびパラメーターのスニッフィングに関する問題が原因です。上記のクエリを UNION アプローチに変更してみてください (こちらの投稿に記載されています) 。つまり、単一の @AuthorType = x AND だけで結合された複数のステートメントができあがり、オプティマイザーは AND ロジックが指定された @AuthorType と一致しない部分を除外し、適切なインデックスを順番にシークできます。 . は次のようになります。

SELECT *
FROM TBooks
WHERE
(--...SOME CONDITIONS)
AND @AuthorType = 1 AND --...DIFFERENT CONDITIONS)
union all
SELECT *
FROM TBooks
WHERE
(--...SOME CONDITIONS)
AND @AuthorType = 2 AND --...DIFFERENT CONDITIONS)
union all
...
于 2009-11-10T16:54:49.720 に答える
0

私は重複を減らしたいという衝動と戦うべきです...しかし、男、それは本当に私には正しく感じられません。

これは「気分」が良くなるでしょうか?

SELECT...たくさんの列と複雑なもの..。
から
((
    MyPKを選択
    TBooksから
    どこ
    (--...いくつかの条件)
    AND @AuthorType = 1 AND --...さまざまな条件)
    ユニオンオール
    MyPKを選択
    TBooksから
    どこ
    (--...いくつかの条件)
    AND @AuthorType = 2 AND --...さまざまな条件)
    ユニオンオール
    ..。
)AS B1
TBooksをB2として参加する
    ON B2.MyPK = B1.MyPK
JOIN...他のテーブル..。

疑似テーブルB1は、PKを取得するための単なるWHERE句です。次に、それを元のテーブル(および必要なその他のテーブル)に結合して、「プレゼンテーション」を取得します。これにより、すべてのUNIONALLでプレゼンテーション列が重複することを回避できます。

これをさらに一歩進めて、最初に一時テーブルにPKを挿入してから、プレゼンテーションの側面で他のテーブルに結合することができます。

これは、ユーザーが何を照会するかについて多くの選択肢がある非常に大きなテーブルに対して行います。

@MyTempTableテーブルを宣言します
((
    MyPK int NOT NULL、
    主キー
    ((
        MyPK
    )。
)。

@LastNameがNULLでない場合
始める
   @MyTempTableに挿入
   ((
        MyPK
   )。
   MyPKを選択
   FROM MyNamesTable
   WHERE LastName=@LastName-これに効率的なインデックスがあるとしましょう
終わり
そうしないと
@CountryがNULLでない場合
始める
   @MyTempTableに挿入
   ((
        MyPK
   )。
   MyPKを選択
   FROM MyNamesTable
   WHERE Country=@Country-これにもインデックスがあります
終わり

...など

SELECT...プレゼンテーション列
FROM @MyTempTable AS T
    MyNamesTableASNに参加する
        ON N.MyPK = T.MyPK-PK参加、V。効率的
    JOIN...他のテーブル..。
        オン ....
WHERE(@LastName IS NULL OR Lastname @LastName)
      AND(@Country IS NULL OR Country @Country)

@MyTempTableを作成するための元のフィルターになかった(たとえば)あいまいなテストを含め、すべてのテストが繰り返されることに注意してください[技術的には@Lastnameのものは必要ありません:)]。

@MyTempTableの作成は、使用可能なパラメーターを最大限に活用するように設計されています。おそらく、@ LastNameと@Countryの両方が利用可能であり、どちらか一方よりもテーブルへの入力がはるかに効率的である場合は、そのシナリオのケースを作成します。

スケーリングの問題?実際に行われているクエリを確認し、改善できるケースを追加します。

于 2009-11-10T17:53:46.177 に答える