web-dev-qa-db-ja.com

WHERE句の変数に対してnullチェックを行う方法は1回だけですか?

次のような大きなテーブルに対するクエリがあります。

declare @myIdParam int = 1

select * 
from myTable
where (@myIdParam is null or myTable.Id = @myIdParam)

Where句には、このような同様の条件がいくつかあり、結合も多数ありますが、これは要約です。

事実上、@ myIdParamがnullの場合、このパラメーターを使用して結果を制限する必要はありません。

私はDBプロではありませんが、私のテストから、このNULLチェックはすべてのレコードに対して行われ、どのような方法でも最適化されていないようです。

Nullチェックを削除し、パラメーターがnullではないと想定すると、クエリはすぐに返されます。それ以外の場合は、最大10秒かかります。

これを最適化する方法はありますか?そのため、チェックは実行時に一度だけ行われますか?

12
Mystagogue

1つの方法は、nullチェックを使用してオプションでwhere句のその部分を追加する動的SQLを使用することです。

declare @myIdParam int = 1
declare @vc_dynamicsql varchar(max)

set @vc_dynamicsql = 'select * from myTable where 1=1'

if @myIdParam is not null
    set @vc_dynamicsql = @vc_dynamicsql + ' and  myTable.Id = @myIdParam'

EXECUTE sp_executesql @vc_dynamicsql
8
Mystagogue

たとえば、列「ISNULL(@var、table.col)」の周りに関数を置くと、SQLのインデックスを使用する機能が削除されます。これを単一のクエリに保持したい場合は、これが本当に最もパフォーマンスの高いオプションです。

@var IS NULL or @var = table.col

それ以外の場合は、2つのオプションがあります。 1つ目は動的SQLであり、@ Mystagogueの答えで十分です。それ以外の場合は、次のような2つのクエリを入力できます。

IF @var is NULL
     SELECT * FROM table
ELSE
     SELECT * FROM table WHERE @var = col

この形式と動的SQLの両方で、実際にはクエリごとに異なるクエリプランが得られます(パフォーマンスが向上する可能性があります)。

4
Kenneth Fisher

まあ、あなたはできます:

_declare @myIdParam int = 1;

select *
from myTable
where nullif(@myIdParam, myTable.Id) is null;
_

ただし、nullif()関数は基本的にcaseのラッパーであることを覚えておいてください。魔法のようにORを排除してクエリを高速化するのは、特効薬ではありません。

0
Roger Wolf