SQL'like 'vs' = 'パフォーマンス


82

この質問は 私が疑問に思っていることを回避しますが、答えは正確にそれに対処していません。

一般に、ワイルドカードを使用する場合、「=」は「like」よりも高速であるように見えます。これは一般通念のようです。ただし、限られた数の異なる固定のハードコードされたvarchar識別子を含む列があり、それらの1つに一致するすべての行を選択するとします。

select * from table where value like 'abc%'

そして

select * from table where value = 'abcdefghijklmn'

'Like'は、最初の3文字をテストして一致を見つけるだけでよいのに対し、 '='は文字列全体を比較する必要があります。この場合、「like」には利点があり、他のすべての条件は同じであるように思われます。

これは一般的な学術的な質問として意図されているため、どのDBでも問題ありませんが、SQL Server2005を使用して発生しました。


23
省略した重要な点の1つvalueは、インデックスが作成されているかどうかです。もしそうなら、それ=はテーブルスキャンを必要としない単純なルックアップでありLIKE、あなたがそれに投げたどんなステートメントからもズボンを打ち負かします。
ダニエルディパオロ2011年

7
@ダニエル私はそれが間違っていると思います。LIKE末尾にワイルドカードが付いているAはSARG可能であるため、インデックスに対して範囲シークを実行し、テーブルスキャンは表示されません。その範囲シークは=ステートメントと非常に便利に競合する可能性があり、多くの場合(すべての満足のいく行が1ページにある場合など)、まったく同じパフォーマンスであり、同じ数の読み取りが必要になる可能性があります。
ErikE 2011年

私の「他のすべてが等しい」は「索引付けされているかどうか」の問題をカバーすることを目的としていましたが、他の回答に対する私のコメントによれば、それがどれほどの違いをもたらすかについて少なくともいくつかの論争があるようです。
MickeyfAgain_BeforeExitOfSO 2011年

私の答えを見てください。最初にインデックスなしでテストしましたが、パフォーマンスは同じです(両方のテーブルスキャンはまったく同じでした)。私のテストシナリオでは、インデックスが作成されると想定しました。そうでない場合、なぜパフォーマンスを気にするのでしょうか。
JNK

5
この質問と答えの「好き」のすべての話は、私たちを女子高生の束のように聞こえさせます。まるで
JulianR 2011年

回答:


64

見る https://web.archive.org/web/20150209022016/http://myitforum.com/cs2/blogs/jnelson/archive/2007/11/16/108354.aspxをください

そこからの引用:

LIKEでのインデックス使用のルールは、大まかに次のようになります。

  • フィルタ条件でequals =が使用され、フィールドにインデックスが付けられている場合、ほとんどの場合、INDEX / CLUSTERED INDEXSEEKが使用されます。

  • フィルタ条件でワイルドカードを使用せずにLIKEを使用する場合(Webレポートに%が含まれる可能性があるパラメータがあり、代わりに完全な文字列を使用する場合など)、インデックスを使用する可能性はほぼ1位です。コストの増加はほとんどありません。

  • フィルタ条件でLIKEが使用されているが、先頭にワイルドカードが付いている場合(Name0 LIKE '%UTER'のように)、インデックスを使用する可能性ははるかに低くなりますが、少なくとも次の範囲全体または一部でINDEXSCANを実行できます。インデックス。

  • ただし、フィルター基準がLIKEを使用しているが、STRING FIRSTで始まり、その後のどこかにワイルドカードがある場合(Name0 LIKE'COMP%ER 'のように)、SQLはINDEX SEEKを使用して、最初に同じ行をすばやく見つけることができます。開始文字を入力し、それらの行を調べて完全に一致するかどうかを確認します。

(また、クエリで他に何が行われているのか、どのテーブルに参加しているのかによっては、SQLエンジンが期待どおりにインデックスを使用しない可能性があることにも注意してください。SQLエンジンは、少しクエリを実行して、最も効率的であり、INDEXSEEKの代わりにINDEXSCANが含まれている可能性があると思われる方法でデータを取得します)


1
そのリンクは死んでいる
baxx

2
@baxxリンクのコピーはウェイバックマシンで利用できます。web.archive.org/web/20150209022016/http://myitforum.com/cs2/...
alphabet5

45

それは測定可能な違いです。

以下を実行します。

Create Table #TempTester (id int, col1 varchar(20), value varchar(20))
go

INSERT INTO #TempTester (id, col1, value)
VALUES
(1, 'this is #1', 'abcdefghij')
GO

INSERT INTO #TempTester (id, col1, value)
VALUES
(2, 'this is #2', 'foob'),
(3, 'this is #3', 'abdefghic'),
(4, 'this is #4', 'other'),
(5, 'this is #5', 'zyx'),
(6, 'this is #6', 'zyx'),
(7, 'this is #7', 'zyx'),
(8, 'this is #8', 'klm'),
(9, 'this is #9', 'klm'),
(10, 'this is #10', 'zyx')
GO 10000

CREATE CLUSTERED INDEX ixId ON #TempTester(id)CREATE CLUSTERED INDEX ixId ON #TempTester(id)

CREATE NONCLUSTERED INDEX ixTesting ON #TempTester(value)

次に:

SET SHOWPLAN_XML ON

次に:

SELECT * FROM #TempTester WHERE value LIKE 'abc%'

SELECT * FROM #TempTester WHERE value = 'abcdefghij'

結果の実行プランは、最初の操作であるLIKE比較のコストが、比較よりも約10倍高いことを示してい=ます。

=比較できる場合は、ぜひ行ってください。


2
実際にテストするための+1。ただし、ショープランを見ただけでは、全体像がわからない場合があります。私は自分でいくつかのテストを行い、予期しないことがあればみんなに知らせます。
トムH

1
トム-本当ですが、それは私に2つが舞台裏で同じように処理されなかったことを十分に示しました。
JNK

1
実行計画に示されているコストが間違っています。実際のパフォーマンスを反映していません。最初のプランでは19.95、SQL Serverの推定行数に基づいているため、実際には実現されない追加の19のキールックアップでのコスト(実際の実行プランでも、表示されるコストは推定サブツリーコストに基づいています)
Martin Smith

テストと約100万行のテストを実行しましたが、どちらの場合もパフォーマンスとクエリプランは同じでした。このマシンには2005がないため、これはSQL2008上にあります。
トムH

1
@ JNK-試してみました-違いはごくわずかですが、格差は同じです。327ミリ秒LIKE、203ミリ秒=。より多くのテストを実行して正確な平均をとった場合、#tempと実際のテーブルの間に実際の違いはないだろうと思います。
ウィルA

13

また、を使用する場合like、一部のSQLフレーバーはインデックスを無視し、パフォーマンスが低下することにも注意してください。これは、例のように「startswith」パターンを使用しない場合に特に当てはまります。

クエリの実行プランを実際に見て、クエリが何をしているのかを確認し、できるだけ推測しないようにする必要があります。

そうは言っても、「で始まる」パターンはSQLサーバーで最適化できます。それはなりますテーブルインデックスを使用します。EF 4.0に切り替えるlikeためのStartsWith、まさにこの理由のために。


2
同様のパターンがクエリの一部であり、ワイルドカードが末尾にある場合、そのソルトに値するリレーショナルデータベースはインデックスを無視しません。値をバインドしていて、データベースがクエリの準備とは別にバインドをサポートしている場合、これは別の話かもしれません。
デイブW.スミス

それは私の腸も私に言っていることですが、私はこの点でSQL Serverの実践的な経験しか持っていないので、特にそれに焦点を合わせました。
ブリンディ2011年

7

valueがインデックス付けされていない場合、両方ともテーブルスキャンになります。このシナリオでのパフォーマンスの違いはごくわずかです。

valueダニエルがコメントで指摘しているように、がインデックス付けされている場合、=はO(log N)パフォーマンスであるインデックスルックアップになります。LIKEをします-インデックスの部分スキャンでは(ほとんどの場合、それがどのように選択的に依存する)結果>= 'abc'< 'abd'これ以上の努力が必要になります=

ここではSQLServerについて話していることに注意してください。すべてのDBMSがLIKEに適しているわけではありません。


二分探索がどのように機能するかをあなたは知らないと思います。どちらの=場合like '...%'もサブツリーは比較関係に基づいて選択されるため、SQLがパターンを認識した場合(および認識した場合)、ケースとケースの両方が同じように動作します。
ブリンディ2011年

ああ、そうです。LIKEは、選択性が十分に高い場合はO(log N)のままですが、動作が悪化する可能性があります-部分スキャンを開始する場所を見つけるためのO(log N)、その後、インデックスを介した順方向読み取りの数終点'abd'に到達しました。
ウィルA

はい。ただし、OPの例では、その範囲に値が1つしかないことを前提としているため、それを念頭に置いて、比較は同じになります。
ブリンディ2011年

有効なポイント-これがOPが言っていたことであるかどうかは完全には明らかではありませんが、そうでないよりもそうである可能性が高いと思います。その場合、パフォーマンスはほぼ同じになります。
ウィルA

LIKEの範囲シークは、=ステートメントと非常に便利に競合する可能性があり、多くの場合(すべての満足する行が1ページにある場合など)、まったく同じパフォーマンスであり、同じ数の読み取りが必要になる可能性があります。 。「もっと努力が必要だ」というのは、一言で言えば間違っていると思います。
ErikE 2011年

6

あなたは間違った質問をしている。データベースでは、重要な作業のパフォーマンスではありません常にSARGability表現、および被覆性全体的なクエリの。オペレーター自体のパフォーマンスはほとんど関係ありません。

では、SARGabilityの観点からどのようLIKE=比較しますか?LIKE、定数で始まらない式で使用される場合(たとえば、使用される場合LIKE '%something')は、定義上、非SARGabaleです。しかし、=それはLIKE 'something%'SARGableになりますか?いいえ。SQLのパフォーマンスに関する質問と同様に、答えはテキストのクエリではなく、展開されたスキーマにあります。これらの式、次の場合にSARGableになる可能性あります、それらを満たすためのインデックスが存在する、ます。

だから、真実は言われます、との間には小さな違いが=ありますLIKEます。しかし、SQLで1人のオペレーターと他のオペレーターのどちらが「速い」かを尋ねるのは、「赤い車と青い車のどちらが速くなるのか」と尋ねるようなものです。色ではなく、エンジンのサイズと車両の重量について質問する必要があります...リレーショナルテーブルの最適化に関する質問に取り組むには、WHERE句(およびその他の句)のインデックスを確認しますが、通常はWHEREで始まります)。


5

mysql 5.5を使用した個人的な例:300万行の1つと1万行の1つである2つのテーブル間に内部結合がありました。

以下のようなインデックスでlikeを使用する場合(ワイルドカードなし)、約30秒かかりました。

where login like '12345678'

'explain'を使用すると、次のようになります。

ここに画像の説明を入力してください

同じクエリで「=」を使用する場合、約0.1秒かかりました。

where login ='600009'

'explain'を使用すると、次のようになります。

ここに画像の説明を入力してください

ご覧のとおりlike、インデックスシークが完全にキャンセルされたため、クエリに300倍の時間がかかりました。


また、実行プランを見て、これを確認することもできます
LittleBobbyTables – Au Revoir 2015年

@LittleBobbyTablesに感謝します。それを見ていきます。
アリス2015

最近のバージョン(5.7)によるものかどうかはわかりませんが、LIKEはここで私の一意のインデックスを壊しません。
セバス2016年

0

多分あなたは全文検索について探しています。

全文検索とは対照的に、LIKETransact-SQL述語は文字パターンでのみ機能します。また、LIKE述部を使用して、フォーマットされたバイナリデータをクエリすることはできません。さらに、大量の非構造化テキストデータに対するLIKEクエリは、同じデータに対する同等のフルテキストクエリよりもはるかに低速です。数百万行のテキストデータに対するLIKEクエリは、返されるまでに数分かかる場合があります。一方、フルテキストクエリは、返される行数に応じて、同じデータに対して数秒以下しかかかりません。


-1

まず最初に、

それらは常に等しいとは限りません

    select 'Hello' from dual where 'Hello  ' like 'Hello';

    select 'Hello' from dual where 'Hello  ' =  'Hello';

物事が常に等しいとは限らない場合、それらのパフォーマンスについて話すことはそれほど重要ではありません。

文字列とchar変数のみで作業している場合は、パフォーマンスについて話すことができます。ただし、一般的に交換可能であるため、likeと "="は使用しないでください。

多くの投稿(上記および他の質問)で見たように、それらが等しい場合、パターンマッチング(照合)のためにlikeのパフォーマンスが遅くなります


場合'Hello 'であるVARCHAR(デフォルト)あなたは正しいですが、それはだ場合CHAR、あなたはそうではありません。それをにキャストすると、CHAR(7)両方ともtrueを返します。また、TRIMvarcharを使用していない場所で何をしているのですか?(注:これは少なくともの場合ですSQL Server 2008r2
abluejelly 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.