web-dev-qa-db-ja.com

LIKEはインデックスを使用しますが、CHARINDEXは使用しませんか?

この質問は 私の古い質問 に関連しています。以下のクエリの実行には10〜15秒かかりました。

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

一部の記事で、CASTCHARINDEXを使用しても、インデックスを作成してもメリットがないことがわかりました。 LIKE '%abc%'は次のように機能しますが、LIKE 'abc%'を使用してもインデックス作成のメリットは得られないという記事もあります。

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-wherehttps://stackoverflow.com/questions/803783/ sql-server-index-any-improvement-for-like-querieshttp://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

私の場合、クエリを次のように書き換えることができます。

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

このクエリは、前のクエリと同じ出力を提供します。列Phone noの非クラスター化インデックスを作成しました。このクエリを実行すると、1秒で実行されます。これは、以前の14秒と比較すると、大きな変化です。

LIKE '%123456789%'はインデックス作成からどのようなメリットがありますか?

リストされている記事に、パフォーマンスが向上しないと記載されているのはなぜですか?

CHARINDEXを使用するようにクエリを書き直そうとしましたが、パフォーマンスはまだ遅いです。 CHARINDEXクエリが行うように見えるのに、なぜLIKEがインデックス作成の恩恵を受けないのですか?

CHARINDEXを使用したクエリ:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

実行計画:

enter image description here

LIKEを使用したクエリ:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

実行計画:

LIKE query plan

22
IT researcher

LIKE '%123456789%'はどのようにインデックス作成から利益を得ますか?

ほんの少しだけ。クエリプロセッサは、テーブル全体(クラスター化インデックス)ではなく、非クラスター化インデックス全体をscan一致を探すことができます。非クラスター化インデックスは一般に、それらが構築されるテーブルよりも小さいため、非クラスター化インデックスのスキャンはより高速になる場合があります。

欠点は、非クラスター化インデックスの定義に含まれていないクエリで必要な列を、行ごとにベーステーブルで検索する必要があることです。

オプティマイザーは、コストの見積もりに基づいて、テーブル(クラスター化インデックス)のスキャンとルックアップによる非クラスター化インデックスのスキャンを決定します。推定コストは、オプティマイザexpectsが選択するLIKEまたはCHARINDEX述語の行数に大きく依存します。

リストされた記事に、パフォーマンスが向上しないと記載されているのはなぜですか?

notがワイルドカードで始まるLIKE条件の場合、SQL Serverは、全体をスキャンする代わりに、インデックスのpartial scanを実行できます。事。たとえば、LIKE 'A%は、インデックスレコード>= 'A'および< 'B'のみをテストすることで正しく評価できます(正確な境界値は照合に依存します)。

この種類のクエリでは、Bツリーインデックスのシーク機能を使用できます。Bツリーを使用して最初のレコード>= 'A'に直接移動し、インデックスキーの順序で前方にスキャンして、失敗したレコードに到達できます< 'B'テスト。 LIKEテストを適用する必要があるのは少数の行だけなので、一般的にパフォーマンスは優れています。

対照的に、LIKE '%Aは、開始または終了する場所がわからないため、部分スキャンに変換できません。すべてのレコードは'A'で終わる可能性があるため、インデックス全体をスキャンしてすべての行を個別にテストすることは改善できません。

CHARINDEXを使用するようにクエリを書き直そうとしましたが、パフォーマンスはまだ遅いです。 LIKEクエリが行うように見えるのに、なぜCHARINDEXがインデックス作成の恩恵を受けないのですか?

クエリオプティマイザーには、どちらの場合でも、テーブル(クラスター化インデックス)のスキャンと非クラスター化インデックス(検索)のスキャンの間に同じ選択肢があります。

コスト見積もりに基づいて、2つの間の選択が行われます。 SQL Serverが2つの方法に対して異なる推定を生成する場合があります。クエリのLIKE形式の場合、見積もりは特別な文字列統計を使用して、かなり正確な見積もりを生成できる場合があります。 CHARINDEX > 0フォームは、推測に基づいて見積もりを生成します。

オプティマイザがCHARINDEXのクラスタ化インデックススキャンとLIKEのルックアップを含む非クラスタ化インデックススキャンを選択するには、さまざまな推定値で十分です。ヒントを使用してCHARINDEXクエリで非クラスター化インデックスを使用するように強制すると、LIKEと同じ計画が得られ、パフォーマンスはほぼ同じになります。

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

実行時に処理される行の数は両方のメソッドで同じになります。この場合、LIKEフォームがより正確な見積もりを生成するだけなので、クエリオプティマイザーがより適切なプランを選択します。

LIKE %thing%検索が頻繁に必要な場合は、- SQL Serverでのトライグラムワイルドカード文字列検索 で説明した手法を検討することをお勧めします。

28
Paul White 9

SQL Serverは、LIKEクエリでは使用できますが、CHARINDEXでは使用できない tries の形式で文字列列の部分文字列の統計を維持します。

これについての詳細は String Summary Statistics セクションを参照してください。

いくつかの重要な注意点は、ワイルドカードのエスケープは、ESCAPEキーワードではなく、独自の角かっこ技法を使用して行う必要があることと、80文字より長い文字列では、最初と最後の40文字のみが使用されることです。

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

行の30%が返されるという不等式述語に標準の推測を使用します。

LIKEクエリ(あなたの場合)では、述語に一致する行がはるかに少ないと推定されます。

先頭のワイルドカードは依然としてインデックスシークを妨げることに注意してください。インデックス全体がスキャンされますが、クラスター化インデックスよりも狭い別のインデックスが使用されます。インデックスを狭めると、クエリで使用されるすべての列がカバーされないため、2番目の計画では、欠落している列を取得するためのキー検索が必要です。

この計画が30%の見積もりで選択されることはほとんどありません。 SQL Serverは、クラスター化インデックス全体をスキャンし、そのような多くのルックアップを回避する方が安価であると見なします。その他の例については、 転換点 に関するこの記事を参照してください。

16
Martin Smith