SQL を使用する場合=
、WHERE
句の代わりに使用する利点はありLIKE
ますか?
特別な演算子がなくてもLIKE
同じ=
ですよね?
SQL を使用する場合=
、WHERE
句の代わりに使用する利点はありLIKE
ますか?
特別な演算子がなくてもLIKE
同じ=
ですよね?
LIKE
と=
は異なる演算子です。ここでのほとんどの回答はワイルドカードのサポートに焦点を当てていますが、これらの演算子の唯一の違いではありません!
=
数値と文字列を操作する比較演算子です。文字列を比較する場合、比較演算子は文字列全体を比較します。
LIKE
文字ごとに比較する文字列演算子です。
問題を複雑にするために、両方の演算子が比較の結果に重要な影響を与える可能性のある照合を使用します。
最初に、これらの演算子が明らかに異なる結果を生成する例を特定しましょう。MySQL のマニュアルから引用させてください。
SQL 標準に従って、LIKE は文字単位で照合を実行するため、= 比較演算子とは異なる結果が生成される可能性があります。
mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
| 1 |
+--------------------------------------+
MySQL マニュアルのこのページは文字列比較関数と呼ば=
れ、議論されていないことに注意してください。これ=
は厳密には文字列比較関数ではないことを意味します。
=
か?SQL 標準 § 8.2 では、=
文字列を比較する方法について説明しています。
2 つの文字列の比較は、次のように決定されます。
a) X の文字数の長さが Y の文字数と等しくない場合、短い文字列は、比較のために、長い文字列の長さに拡張されたそれ自体のコピーで効果的に置き換えられます。 1 つ以上のパッド文字の右側に連結することにより、パッド文字は CS に基づいて選択されます。CS に NO PAD 属性がある場合、埋め込み文字は実装依存の文字であり、CS のどの文字列よりも照合が少ない X および Y の文字セット内の文字とは異なります。それ以外の場合、埋め込み文字は <スペース> です。
b) X と Y の比較の結果は、照合シーケンス CS によって与えられます。
c) 照合順序によっては、2 つの文字列は、長さが異なっていたり、文字列が異なっていたりしても、等しいものとして比較される場合があります。演算 MAX、MIN、DISTINCT がグループ化列を参照し、UNION、EXCEPT、および INTERSECT 演算子が文字列を参照する場合、これらの演算によってそのような等しい値のセットから選択される特定の値は実装依存です。
(強調を追加しました。)
これは何を意味するのでしょうか?これは、文字列を比較するとき、=
演算子が現在の照合の薄いラッパーであることを意味します。照合は、文字列を比較するためのさまざまな規則を持つライブラリです。MySQL からのバイナリ照合の例を次に示します。
static int my_strnncoll_binary(const CHARSET_INFO *cs __attribute__((unused)),
const uchar *s, size_t slen,
const uchar *t, size_t tlen,
my_bool t_is_prefix)
{
size_t len= MY_MIN(slen,tlen);
int cmp= memcmp(s,t,len);
return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}
この特定の照合では、たまたまバイト単位で比較されます (これが「バイナリ」と呼ばれる理由です。文字列に特別な意味はありません)。他の照合は、より高度な比較を提供する場合があります。
たとえば、大文字と小文字を区別しない比較をサポートするUTF-8 照合順序を次に示します。コードは長すぎてここに貼り付けることができませんが、そのリンクに移動して の本文を読んでくださいmy_strnncollsp_utf8mb4()
。この照合では、一度に複数のバイトを処理でき、さまざまな変換 (大文字と小文字を区別しない比較など) を適用できます。=
演算子は、照合の気まぐれから完全に抽象化されています。
LIKE
か?SQL 標準 § 8.5 では、LIKE
文字列を比較する方法について説明しています。
<述語>
M LIKE P
次のような部分文字列への M の分割が存在する場合、 は true です。
i) M の部分文字列は、M の 0 個以上の連続した <文字表現> のシーケンスであり、M の各 <文字表現> は、正確に 1 つの部分文字列の一部です。
ii) P の i 番目の部分文字列指定子が任意の文字指定子である場合、M の i 番目の部分文字列は任意の単一の <文字表現> です。
iii) P の i 番目の部分文字列指定子が任意の文字列指定子である場合、M の i 番目の部分文字列は、0 個以上の <文字表現> の任意のシーケンスです。
iv) P の i 番目の部分文字列指定子が任意の文字指定子でも任意の文字列指定子でもない場合、M の i 番目の部分文字列は、<like 述語> の照合シーケンスに従って、その部分文字列指定子と等しくなります。 <space> 文字を M に追加し、その部分文字列指定子と同じ長さを持ちます。
v) M の部分文字列の数は、P の部分文字列指定子の数と同じです。
(強調を追加しました。)
これはかなり長いので、分解してみましょう。項目 ii および iii は、それぞれワイルドカード_
およびを参照し%
ます。P
ワイルドカードが含まれていない場合は、項目 iv のみが適用されます。これは、OP によって提起された関心のケースです。
この場合、現在の照合順序を使用して、各「部分文字列」(個々の文字) をM
各部分文字列と比較します。P
肝心なのは、文字列を比較するとき、一度に 1 文字ずつ比較=
しながら、文字列全体をLIKE
比較することです。どちらの比較も現在の照合順序を使用します。この違いは、この投稿の最初の例で証明されているように、場合によっては異なる結果につながります。
どちらを使用する必要がありますか? ユースケースに適したものを使用する必要があります。比較演算子を切り替えて時期尚早に最適化しないでください。
等号 (=) 演算子は、「2 つの値を比較して等しいかどうかを比較する比較演算子」です。つまり、SQL ステートメントでは、式の両辺が等しくない限り、true は返されません。例えば:
SELECT * FROM Store WHERE Quantity = 200;
LIKE 演算子は、「ワイルドカード文字を含むパターン文字列に対して文字列値を」照合しようとする「パターン一致比較を実装」します。例えば:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKE は通常、文字列と equals (私が信じている) でのみ使用されます。等号演算子は、ワイルドカード文字をリテラル文字として扱います。返される結果の違いは次のとおりです。
SELECT * FROM Employees WHERE Name = 'Chris';
と
SELECT * FROM Employees WHERE Name LIKE 'Chris';
通常、LIKE を使用するとパターン マッチとして時間がかかりますが、同じ結果が返されます。でも、
SELECT * FROM Employees WHERE Name = 'Chris%';
と
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
「=」を使用すると、「Chris%」が返される結果のみが返され、LIKE 演算子は「Chris」で始まるすべての結果が返されます。
それが役立つことを願っています。ここでいくつかの良い情報を見つけることができます。
これは、質問SQL 'like' vs '=' performanceに対する私の別の回答のコピー/貼り付けです:
mysql 5.5 を使用した個人的な例: 300 万行のテーブルと 10,000 行のテーブルの 2 つのテーブル間で内部結合を行いました。
以下のように (ワイルドカードなしで) インデックスに like を使用すると、約 30 秒かかりました。
where login like '12345678'
「説明」を使用すると、次のようになります。
同じクエリで「=」を使用すると、約 0.1 秒かかりました。
where login ='12345678'
「説明」を使用すると、次のようになります。
ご覧のとおりlike
、インデックス シークが完全にキャンセルされたため、クエリに 300 倍の時間がかかりました。
LIKE
と=
は異なります。LIKE
検索クエリで使用するものです。_
(単純文字ワイルドカード) や%
(複数文字ワイルドカード) などのワイルドカードも使用できます。
=
完全一致が必要な場合に使用する必要があり、高速になります。
違いの 1 つは、LIKE でワイルドカードを使用できることを除けば、末尾のスペースにあります。= 演算子は末尾のスペースを無視しますが、LIKE は無視しません。
データベースシステムに依存します。
通常、特殊文字がない場合、yes、=、および LIKE は同じです。
ただし、一部のデータベース システムでは、演算子が異なると照合設定が異なる方法で処理される場合があります。
たとえば、MySQL では、文字列の = を使用した比較では、デフォルトで常に大文字と小文字が区別されないため、特殊文字を使用しない LIKE は同じです。他の RDBMS では、LIKE は大文字と小文字を区別しませんが、= は大文字と小文字を区別しません。
この例では、varcharcol が含まれ''
ておらず、この列に対して空のセルがないことを当然のことと考えています。
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
最初のものは 0 行の出力になり、2 番目のものはリスト全体を表示します。= は厳密に一致するケースですが、like はフィルターのように機能します。フィルターに基準がない場合、すべてのデータが有効です。
のように - その目的のおかげで動作が少し遅くなり、varchar および同様のデータでの使用を目的としています。
パフォーマンスに関する元の質問に答えるために、それはインデックスの使用率に帰着します。単純なテーブル スキャンが発生する場合、「LIKE」と「=」は同一です。インデックスが含まれる場合、LIKE 句の形成方法によって異なります。具体的には、ワイルドカードの場所は?
次の点を考慮してください。
CREATE TABLE test(
txt_col varchar(10) NOT NULL
)
go
insert test (txt_col)
select CONVERT(varchar(10), row_number() over (order by (select 1))) r
from master..spt_values a, master..spt_values b
go
CREATE INDEX IX_test_data
ON test (txt_col);
go
--Turn on Show Execution Plan
set statistics io on
--A LIKE Clause with a wildcard at the beginning
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '%10000'
--Results in
--Table 'test'. Scan count 3, logical reads 15404, physical reads 2, read-ahead reads 15416, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index SCAN is 85% of Query Cost
--A LIKE Clause with a wildcard in the middle
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '1%99'
--Results in
--Table 'test'. Scan count 1, logical reads 3023, physical reads 3, read-ahead reads 3018, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost for test data, but it may result in a Table Scan depending on table size/structure
--A LIKE Clause with no wildcards
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col like '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO
--an "=" clause = does Index Seek same as above
DBCC DROPCLEANBUFFERS
SELECT txt_Col from test where txt_col = '10000'
--Results in
--Table 'test'. Scan count 1, logical reads 3, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Index Seek is 100% of Query Cost
GO
DROP TABLE test
また、"=" と "LIKE" を使用した場合、クエリ プランの作成にほとんど違いがない場合もあります。
= を使用すると、実行時にクエリを作成するときに、文字列内でのワイルドカードと特殊文字の競合を回避できます。
これにより、LIKE 句に挿入されて意図した結果が生成されない可能性がある特殊なワイルドカード文字をすべてエスケープする必要がなくなり、プログラマーの作業が楽になります。結局のところ、= は 99% のユース ケース シナリオです。毎回それらをエスケープしなければならないのは面倒です。
90年代に目を転がす
また、少し遅いのではないかと思いますが、パターンにワイルドカードがない場合、それが重要であるとは思えません。
完全一致を検索する場合は、= と LIKE の両方を使用できます。
この場合、"=" を使用すると少し高速になります (完全一致を検索します)。これは、SQL Server Management Studio で同じクエリを 2 回実行することで確認できます。1 回は "=" を使用し、1 回は "LIKE" を使用し、次に、「クエリ」/「実際の実行計画を含める」を使用します。
2 つのクエリを実行すると、結果が 2 回表示され、さらに 2 つの実際の実行計画が表示されます。私の場合、それらは 50% 対 50% に分割されましたが、「=」実行プランの「推定サブツリー コスト」は小さくなります (左端の「SELECT」ボックスにカーソルを合わせると表示されます)。大きな違いではありません。
ただし、LIKE 式でワイルドカードを使用して検索を開始すると、検索のパフォーマンスが低下します。検索 "LIKE Mill%" は依然として非常に高速です。SQL Server は、その列にインデックスがあればそれを使用できます。"LIKE %expression%" の検索は非常に遅くなります。これは、SQL Server がこの検索を満たすことができる唯一の方法は、完全なテーブル スキャンを実行することだからです。したがって、LIKE には注意してください。
マルク
=
ワイルドカードに加えて、 ANDの違いはLIKE
、SQL サーバーの種類と列の型の両方によって異なります。
次の例を見てください。
CREATE TABLE testtable (
varchar_name VARCHAR(10),
char_name CHAR(10),
val INTEGER
);
INSERT INTO testtable(varchar_name, char_name, val)
VALUES ('A', 'A', 10), ('B', 'B', 20);
SELECT 'VarChar Eq Without Space', val FROM testtable WHERE varchar_name='A'
UNION ALL
SELECT 'VarChar Eq With Space', val FROM testtable WHERE varchar_name='A '
UNION ALL
SELECT 'VarChar Like Without Space', val FROM testtable WHERE varchar_name LIKE 'A'
UNION ALL
SELECT 'VarChar Like Space', val FROM testtable WHERE varchar_name LIKE 'A '
UNION ALL
SELECT 'Char Eq Without Space', val FROM testtable WHERE char_name='A'
UNION ALL
SELECT 'Char Eq With Space', val FROM testtable WHERE char_name='A '
UNION ALL
SELECT 'Char Like Without Space', val FROM testtable WHERE char_name LIKE 'A'
UNION ALL
SELECT 'Char Like With Space', val FROM testtable WHERE char_name LIKE 'A '
MS SQL Server 2012を使用するとLIKE
、列タイプが の場合を除いて、末尾のスペースは比較で無視されますVARCHAR
。
MySQL 5.5を使用すると、との両方で、では末尾のスペースが無視されますが、では無視され=
ません。LIKE
CHAR
VARCHAR
PostgreSQL 9.1を使用すると、スペースは=
とLIKE
usingの両方で重要になりますが、では意味VARCHAR
がありませんCHAR
(ドキュメントを参照してください)。
での動作LIKE
も で異なりCHAR
ます。
上記と同じデータを使用しCAST
て、列名に明示的に使用すると、違いも生じます。
SELECT 'CAST none', val FROM testtable WHERE char_name LIKE 'A'
UNION ALL
SELECT 'CAST both', val FROM testtable WHERE
CAST(char_name AS CHAR) LIKE CAST('A' AS CHAR)
UNION ALL
SELECT 'CAST col', val FROM testtable WHERE CAST(char_name AS CHAR) LIKE 'A'
UNION ALL
SELECT 'CAST value', val FROM testtable WHERE char_name LIKE CAST('A' AS CHAR)
これは、「CAST both」と「CAST col」の行のみを返します。
LIKE キーワードには、間違いなく「パフォーマンス値札」が付いています。とはいえ、クエリでワイルドカード文字を使用する可能性のある入力フィールドがある場合は、入力にワイルドカードのいずれかが含まれている場合にのみLIKE を使用することをお勧めします。それ以外の場合は、比較に等しい標準を使用します。
よろしくお願いします...
実際には、クエリで何をしたいかによって決まります。完全一致を意味する場合は、= を使用します。あいまい一致を意味する場合は、LIKE を使用します。あなたが言いたいことを言うことは、通常、コードの良いポリシーです。
Oracle では、ワイルドカードを使用しない「like」は「equals」と同じ結果を返しますが、追加の処理が必要になる場合があります。Tom Kyte によると、Oracle はリテラルを使用する場合、ワイルドカードのない「like」を「equals」として扱いますが、バインド変数を使用する場合は扱いません。
=
そしてLIKE
同じではありません。
=
正確な文字列に一致LIKE
ワイルドカード (%) を含む可能性のある文字列に一致します