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


11

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

declare @myIdParam int = 1

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

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

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

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

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

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


1
この答えを見てください:stackoverflow.com/questions/3415582/…tl ; dr useOPTION(RECOMPILE)
vercelli

@vercelliこれはトリックを行います。この質問は本当にオプションのパラメーターに関するものであることを考えると、リンクしたものの複製だと思います。
Mystagogue

おそらく、それは6年前からの投稿です。SqlServer 2014または2016では、新しいアプローチがあるかもしれません。(私は2014年に再コンパイルせずにテストし、永遠に
費やしました

実際のクエリには多くのオプションパラメータがあるため、動的SQLが最高のパフォーマンスを提供します。この件に関する詳細な記事については、sommarskog.se / dyn-search.htmlを参照してください。
Dan Guzman、

リンクされた質問vercelliで概説されているようにWITH RECOMPILEを使用する@DanGuzmanは、クエリ時間を1分足らずから非常に選択的な基準で実際に瞬時に短縮しました。これは、パフォーマンスと読みやすさのバランスをとるための最良のオプションと考えています。
Mystagogue

回答:


8

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

2
私はこれを絶対にしたくないのですが、それは解決策です。私の希望は、誰かがもっと良い人と一緒に来ることです。
Mystagogue

1
これは、このクラスの検索クエリを処理する最良の方法です。@vercelliで言及stackoverflowの答えがこれを行う方法のための偉大な参照が含まれています。
Max Vernon

これは最良の方法ですが、@ paramsパラメータsp_ExecuteSQLが欠落しており、@vc_dynamicsqlパラメータをにする必要があることに気付きましたNVARCHAR
ジェームズアンダーソン

4

たとえば、列「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の両方で、実際にはクエリごとに異なるクエリプランが得られます(パフォーマンスが向上する可能性があります)。


問題のSQLはISNULLまたはその他の関数を使用していません。
Mystagogue

@MystagogueI削除された回答を参照していました。
ケネスフィッシャー

0

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

declare @myIdParam int = 1;

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

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


where句で関数を使用すると、インデックスの使用が妨げられるため(または聞いたことがあるため)、パフォーマンスに悪影響を及ぼします
Mystagogue

@Mystagogue、はい-通常、検索条件が非SARGableになります。悲しいかな、これが、動的SQLや複数UNIONのに頼らずに質問に答える方法を私が知る唯一の方法です。この正確なタスクがあったときに、動的SQLを選択しました。
ロジャーウルフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.