SQL Server インデックス - LIKE クエリの改善点はありますか?
-
03-07-2019 - |
質問
かなり大きなテーブルを実行するクエリがありますが、残念なことに、ユーザーが部分的な名前などで検索できるように、いくつかの varchar フィールドで LIKE '%ABC%' を使用する必要があります。SQLサーバー2005
これらの varchar フィールドにインデックスを追加すると、LIKE を使用する場合の選択クエリのパフォーマンスの点で役立ちますか、それとも基本的にインデックスを無視して、そのような場合にフル スキャンを実行しますか?
LIKE 使用時のパフォーマンスを向上させる他の方法はありますか?
解決
これらの列にフルテキスト検索を追加し、SQL Serverのフルテキストクエリ機能を使用する場合のみ。
そうでない場合、いいえ、インデックスは役に立ちません。
他のヒント
インデックスを追加することにより、パフォーマンスが向上する可能性があります。詳細に大きく依存します:)
述語列は、行の合計サイズのうちどれくらいですか?何行一致すると予想しますか?述部に一致するすべての行を返す必要がありますか、それとも上位1行または上位n行のみを返す必要がありますか?
高い選択性/一意性(返される行が少ない)で値を検索しており、述部の列が行サイズ全体の小さな部分である場合、インデックスは非常に便利です。それでもスキャンは行われますが、インデックスはソーステーブルよりもページあたりの行数が多くなります。
これは、合計行サイズが検索対象の列サイズよりもはるかに大きい例です。
create table t1 (v1 varchar(100), b1 varbinary(8000))
go
--add 10k rows of filler
insert t1 values ('abc123def', cast(replicate('a', 8000) as varbinary(8000)))
go 10000
--add 1 row to find
insert t1 values ('abc456def', cast(replicate('a', 8000) as varbinary(8000)))
go
set statistics io on
go
select * from t1 where v1 like '%456%'
--shows 10001 logical reads
--create index that only contains the column(s) to search across
create index t1i1 on t1(v1)
go
select * from t1 where v1 like '%456%'
--or can force to
--shows 37 logical reads
実際の実行計画を見ると、エンジンがインデックスをスキャンし、一致する行でブックマーク検索を実行したことがわかります。または、このプランを単独で使用することに決めていない場合は、オプティマイザーに直接インデックスを使用するように指示できます。 *から(index(t1i1))でt1を選択します。v1は '%456%'のようになります
選択性の高い少数の列のみを検索する列が多数ある場合は、複数のインデックスを作成し、削減アプローチを使用できます。例えば。最初に高度に選択的なインデックスからIDのセット(またはPKが何であるか)を決定し、次にその小さなPKのセットに対してフィルターで選択性の低い列を検索します。
常に大きな行セットを返す必要がある場合は、ほぼ確実にテーブルスキャンを使用することをお勧めします。
したがって、可能な最適化は、テーブル定義の詳細とデータの選択性に大きく依存します。
HTH! -エイドリアン
パフォーマンスを改善できる唯一の方法(フルテキストインデックスの使用以外)は、「LIKE ABC%」を使用することです。 -検索語の両端にワイルドカードを追加しないでください-その場合、インデックスが機能する可能性があります。
検索用語の両端にワイルドカードを使用する必要があるという要件がある場合、運が悪い...
マーク
「%ABC%」のように、常に完全なテーブル スキャンが実行されます。それを回避する方法はありません。
代替アプローチがいくつかあります。まず全文検索ですが、これはまさにこの種の問題向けに設計されているので、最初にそれを見ていきます。
あるいは、状況によっては、データを非正規化し、ターゲット フィールドを適切なトークンに前処理してから、これらの考えられる検索語を別の 1 対多の検索テーブルに追加することが適切な場合もあります。たとえば、データが常にパターン「AAA/BBB/CCC」を含むフィールドで構成されており、ユーザーが BBB で検索している場合、挿入/更新時にそれをトークン化します (削除時に削除します)。これは、アプリケーション コードではなくトリガーを使用するケースの 1 つです。 多くの 好ましい。
これは実際には最適な手法ではなく、データがこの手法によく一致し、何らかの理由で全文検索を使用したくない場合にのみ使用する必要があることを強調しなければなりません (また、同様のスキャンでのデータベースのパフォーマンスは実際には低下します)。受け入れられません)。また、将来的にはメンテナンスの問題も発生する可能性があります。
その列の統計を作成します。 SQL Server 2005では、文字列内検索が最適化されているため、そのメリットが得られる可能性があります。