1

私はテーブルを持っています。それを と呼びましょうHistory。主キー (別名クラスター化インデックス) は と呼ばれHIST_IDます。このテーブルには、開発 DB に約 2300 行あります。ここで、次の 2 つのクエリを検討してください。

クエリ 1:

declare @x int
set @x = 14289

select * from History where hist_id=@x

クエリ 2:

declare @x int
set @x = 14289

select * from History where hist_id=@x or @x is null

唯一の違いはor @x is null、末尾にあります。ただし、最初のクエリはインデックス シークを実行し、2 番目のクエリはインデックス スキャンを実行します。何を与える?

先制応答 - いいえ、オプション (再コンパイル) は役に立ちません。

追加:推測ではなく、確固たる議論のある事実が欲しい. 私自身、これについて考えられる理由を十数個推測できます。しかし、ここで本当の問題は何ですか?

4

3 に答える 3

1

渡される/使用されるパラメーターとは別に計画が作成されることをお勧めします。したがって、本質的には、(@x の値に応じて) すべての行を返す必要があります。そのため、クエリ プランは、受け取ることができるパラメーターの最悪のシナリオを処理しています。

たとえば、@x の入力が null の場合、クエリは強制的にすべての行を返すことになります。これは、すべての行が常に true を返すリテラル方程式/述語を満たすためです。クエリ プランで @x のすべての値をカバーするには、スキャンを実行するプランを生成する必要があります。

于 2009-10-23T14:32:33.477 に答える
0

オプティマイザーはそれが有益であると判断したと思います。別の方法は、あなたが書いたのと同じ計画を使用することです

select * from History where hist_id=@x
union all
select * from History where @x is null

このようにクエリを書き直すことはできますが、オプティマイザが単独でこれを行うことができると確信しています。null 値はいくつありますか?

編集:私は質問を読み違えて、あなたが望むと思ったことがわかりました WHERE (@x = hist_id OR hist_id is null)。実際、動的基準が必要です。この記事をチェックしてください。WITH(RECOMPILE) を指定すると、この種類のクエリは SQL2k8 で機能するはずでしたが、厄介なバグのため、このサポートは削除されたことに注意してください。

于 2009-10-23T14:26:41.943 に答える
0

もちろんインデックススキャンです。

「@x IS NULL」の適切な述語がないため、クラスター化インデックス スキャン = テーブル スキャンです。

パラメータ化され、キャッシュされたプランは一般的であり、@x = NULL または @x = 値に対して機能します。@x を定義しない場合は、同じ計画を取得する必要があります。

「12345 IS NULL」をコーディングした場合、これは検出されて無視されます。

クエリ プランで定数がどのように扱われるかについてのブログ記事が見つかりません。要点は、それらが一般化されており、計画の再利用を可能にする短絡が起こらないということです。

于 2009-10-23T14:33:53.600 に答える