3

次のようなクエリがあります。

select top(10) * from dbo.myTable where DisplayName like 'farm%'

ワイルドカードが末尾にあるため、DisplayName でインデックス シークが発生します。ただし、これを行う場合は同じではありません。

declare @val varchar(200) = 'farm'
select top(10) * from dbo.myTable where DisplayName like @val + '%'

またはこれ:

declare @val varchar(200) = 'farm%'
select top(10) * from dbo.myTable where DisplayName like @val

このような場合、SQL は非常に低速なインデックス スキャン操作にフォールバックします。配置されている値は実行時に提供されるパラメーターであるため、明らかに最初のクエリを目的に使用することはできません。

私ができる方法はありますか:

  1. SQL インデックスが値をシークしていることを確認します。
  2. このロジックをストアド プロシージャにプリコンパイルします。クエリは高速である必要があるため、実行ごとに再コンパイルを強制するメソッドに頼る必要はありません (コンパイルのオーバーヘッド + インデックス シークはインデックス スキャンよりも高速ですが)。

ワイルドカード文字の有無が実行計画に影響することは認識していますが、SQL は、クエリ #2 のようにワイルドカードを値に連結したとしても、ワイルドカードが常に使用されていることを認識していないようです。

4

2 に答える 2

3

SQL Server では、これらのクエリに範囲シークを使用できます(変数の先頭にワイルドカードが含まれている場合、範囲はインデックス全体になります)。

この場合、そうすることを選択していない場合は、変数の使用が選択性を正確に推定していないことを意味している可能性があります。ヒントを追加してOPTION (RECOMPILE)、実際の変数値を考慮することができます。

于 2012-09-09T12:22:00.763 に答える
1

私が select * を主キーと DisplayName 列のみに置き換えたときに SQL が実際にインデックス シークを行ったため、Martin は正しいと思います。

さらに、LIKE 'farm%' は DisplayName >= 'farm' AND DisplayName < 'farN' として実装されていたため、LIKE 演算子を完全に使用しないことにしました。

select top(10) * from dbo.EPFSuppliers with(forceseek) 
where DisplayName >= @str and DisplayName < left(@str,len(@str)-1) + char(ascii(right(@str,1)) + 1)

SQL は一致する行数を 729 と見積もっているため、forceseek ヒントが必要です。これは、私の状況ではまったく非現実的な数です。

この方法は、エスケープ文字を削除するために文字列を前処理する必要があるワイルドカードを使用するよりも優れていると思います。

于 2012-09-09T13:25:12.037 に答える