11

フルテキストインデックスを使用して製品(250,000行)を検索するストアドプロシージャがあります。なぜこれらの2つのクエリのパフォーマンスが異なるのですか?

保存されたprocは、全文検索条件であるパラメータをとります。このパラメータはnullになる可能性があるため、ヌルチェックを追加して、クエリの実行が突然遅くなりました。ここで

-- This is normally a parameter of my stored proc 
DECLARE @Filter VARCHAR(100) 
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)' 

-- #1 - Runs < 1 sec 
SELECT TOP 100 ID FROM dbo.Products 
WHERE CONTAINS(Name, @Filter) 

-- #2 - Runs in 18 secs 
SELECT TOP 100 ID FROM dbo.Products 
WHERE @Filter IS NULL OR CONTAINS(Name, @Filter) 

実行計画は、次のとおりです。

クエリ#1 Execution plant #1

クエリ#2 Execution plant #2

私は実行計画に精通していないだと認めなければなりません。唯一明らかな違いは、結合が異なることです。私はヒントを追加しようとしますが、私のクエリには参加していないので、それをどうやって行うのか分かりません。

また、IX_SectionIDというインデックスが使用されているのはなぜか分かりません。なぜなら、それはカラムのSectionIDのみを含むインデックスであり、そのカラムはどこでも使用されていないからです。

答えて

8

ORは、パフォーマンスをつぶすので、それをこのように行うことができます。この記事で

DECLARE @Filter VARCHAR(100) 
SET @Filter = 'FORMSOF(INFLECTIONAL, robe)' 

IF @Filter IS NOT NULL 
BEGIN 
    SELECT TOP 100 ID FROM dbo.Products 
    WHERE CONTAINS(Name, @Filter) 
END 
ELSE 
BEGIN 
    SELECT TOP 100 ID FROM dbo.Products 
END 

ルック:Dynamic Search Conditions in T-SQL by Erland Sommarskogと、この質問:SQL Server 2008 - Conditional Queryを。

+0

ニースの記事 - OPTION(RECOMPILE) '追加'実際に第二のクエリのパフォーマンスの問題を(解決が別の問題は、 '()'昇給が含まれていることですパラメータがNULLの場合はエラーですが、別の問題です)。 –

1

あなたはOR条件を導入しました。 ほとんどの場合、NULLを明示的にチェックし、あなたのメソッドに対して1つのクエリを実行するほうがずっと速いです。例えば

この試してみてください。最初のクエリプランは簡単に見えます

IF @Filter IS NULL 
BEGIN 
SELECT TOP 100 ID FROM dbo.Products 
END 
ELSE 
BEGIN 
SELECT TOP 100 ID FROM dbo.Products 
WHERE @Filter CONTAINS(Name, @Filter) 
END 
3

を:

  1. の他の列を検索するCONTAINS(Name, @Filter)
  2. インデックス・スキャンを解決するために、フルテキスト検索一致する行
  3. ハッシュ結合を使用して2つを結合します。

concatenation operatorは、2つのレコードセットの和集合を形成します。

  1. をインデックス・スキャン(後に他の列を検索するために使用)
  2. 一定のスキャン:2番目のクエリがやっているようなので、それが見えます。私はあなたのクエリがパラメータ化されていないものとして扱っていると仮定しているので、クエリープランは@Filterという他の値では機能しません。正しければ、定数スキャンは@Filter is not nullを解決します。
  3. ループから空のセットでCONTAINS(Name, @Filter)
  4. 組合3の結果を解決するために、フルテキスト検索は、他の列を検索するには、1と4の結果を結合し

ハッシュ・ジョイン速度のためにメモリを交換する。システムに十分なメモリがある場合は、ループ結合よりもはるかに高速です。これは10〜100倍の減速を簡単に説明することができます。

一つの修正は、2つの異なるクエリを使用することです:

if @Filter is null 
    SELECT TOP 100 ID FROM dbo.Products 
else 
    SELECT TOP 100 ID FROM dbo.Products WHERE CONTAINS(Name, @Filter) 
+0

興味深い - 2番目のクエリでハッシュ結合を強制する方法はありますか? –

+0

ええ、内部ハッシュ結合を使って書き直すことはできますが、それはやや複雑です。 Sommarskogの記事のソリューションの1つを使用する方が良いでしょう。 – Andomar

関連する問題