SQLを使用する場合、WHERE
の代わりにLIKE
句で=
を使用する利点はありますか?
特別な演算子がなければ、LIKE
と=
は同じですね。
LIKE
と=
は異なる演算子です。ここでの回答の大部分はワイルドカードのサポートに焦点を当てています。これは、これらの演算子の唯一の違いではありません。
=
は、数字と文字列を操作する比較演算子です。文字列を比較するとき、比較演算子は全体の文字列を比較します。
LIKE
はcharacter by characterを比較する文字列演算子です。
問題を複雑にするために、両方の演算子は 照合 を使用します。これは比較の結果に重要な影響を与える可能性があります。
まず、これらの演算子が明らかに異なる結果を生み出す例を見てみましょう。 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属性が指定されている場合、埋め込み文字は、XおよびYの文字セット内のいずれの文字とも異なる実装依存の文字で、CSの下の文字列よりも小さくなります。それ以外の場合、埋め込み文字はaです。
b)XとYの比較結果は、照合シーケンスCSによって与えられます。
c)照合順序によっては、2つの文字列の長さが異なっていたり、異なる文字列が含まれていても、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);
}
この特定の照合は、バイトごとに比較されます(これが「バイナリ」と呼ばれる理由です - 文字列に特別な意味を与えることはありません)。他の照合はより高度な比較を提供するかもしれません。
たとえば、大文字と小文字を区別しない比較をサポートする TF-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以上の<文字表現> sの任意のシーケンスです。
iv)Pのi番目の部分文字列指定子が任意の文字指定子でも任意の文字列指定子でもない場合、Mのi番目の部分文字列は照合に従ってその部分文字列指定子と等しくなります。 <space>文字をMに追加せずに<like predicate>のシーケンスを指定し、その部分文字列指定子と同じ長さにする
v)Mの部分文字列の数が、Pの部分文字列指定子の数と等しい。
(強調を加えた。)
これはかなり言葉が多いので、それを分解しましょう。項目iiとiiiは、それぞれワイルドカード_
と%
を参照します。 P
にワイルドカードが含まれていない場合は、項目ivのみが適用されます。これは、OPが提起した利害の場合です。
この場合、現在の照合順序を使用して、M
内の各 "部分文字列"(個々の文字)をP
内の各部分文字列と比較します。
要するに、文字列を比較するとき、=
は文字列全体を比較し、LIKE
は一度に1文字を比較します。どちらの比較でも現在の照合順序が使用されます。この記事の最初の例で証明されているように、この違いは場合によっては異なる結果につながります。
どちらを使うべきですか?誰もあなたにそれを言うことはできません - あなたはあなたのユースケースに合ったものを使う必要があります。比較演算子を切り替えて時期尚早に最適化しないでください。
Equals(=)演算子は、「比較演算子は2つの値が等しいかどうかを比較する」です。言い換えれば、SQL文では、式の両側が等しくなければtrueを返しません。例えば:
SELECT * FROM Store WHERE Quantity = 200;
LIKE演算子は、「文字列値をワイルドカード文字を含むパターン文字列と照合することを試みる」「パターン照合比較を実装する」。例えば:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKEは一般的に文字列でのみ使用され、等号(私は信じている)の方が速いです。等号演算子は、ワイルドカード文字をリテラル文字として扱います。返される結果の違いは以下のとおりです。
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」で始まるものはすべて返されるため、異なる結果が返されます。
それが役立つことを願っています。いくつかの良い情報が見つかります ここ 。
LIKE
と=
は異なります。 LIKE
は、検索クエリで使用するものです。 _
(単純な文字のワイルドカード)や%
(複数文字のワイルドカード)のようなワイルドカードも使用できます。
完全に一致させたい場合は=
を使用してください。
これは質問に対する私の別の答えのコピー/貼り付けです SQLのような 'vs' = 'パフォーマンス :
Mysql 5.5を使用した個人的な例:私は2つのテーブル、300万行のうちの1行と1万行のうちの1行の間に内部結合を持っていました。
以下のように索引にlikeを使用すると(ワイルドカードなし)、約30秒かかりました。
where login like '12345678'
「説明」を使用すると、次のようになります。
同じクエリで '='を使用した場合、約0.1秒かかりました。
where login ='12345678'
「説明」を使用すると、次のようになります。
ご覧のとおり、like
はインデックスの検索を完全にキャンセルしたため、クエリには300倍以上の時間がかかりました。
1つの違いは、LIKEでワイルドカードを使用する可能性とは別に、末尾のスペースにあります。=演算子は末尾のスペースを無視しますが、LIKEは無視しません。
データベースシステムに依存します。
通常、特殊文字はありません、yes、=、およびLIKEは同じです。
ただし、データベースシステムによっては、照合設定を異なる演算子で異なる方法で処理することがあります。
たとえば、MySQLでは= on文字列との比較ではデフォルトで常に大文字と小文字が区別されないため、特殊文字を使用しないLIKEでも同じです。他のRDBMSでは、LIKEは大文字と小文字を区別しませんが、=はしません。
この例では、varcharcolに''
が含まれておらず、この列に対して空のセルがないことは当然のことと考えます。
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
最初のものは0行を出力し、2番目のものはリスト全体を表示します。 =は厳密に一致するケースで、likeはフィルタのように機能します。 filterに基準がない場合は、すべてのデータが有効です。
のように - その目的のおかげで少し遅く動作し、varcharと同様のデータで使用するためのものです。
=を使用すると、実行時にクエリを作成するときに、文字列内でのワイルドカードと特殊文字の競合が回避されます。
これにより、LIKE句に含まれている可能性のある特殊なワイルドカード文字をすべてエスケープする必要がなくなり、意図した結果が得られないため、プログラマの作業が楽になります。結局、=は99%のユースケースシナリオであり、毎回それらをエスケープする必要があるのは面倒です。
90年代に目をロール
少し遅いと思いますが、パターンにワイルドカードが含まれていなければ意味がありません。
完全に一致するものを検索する場合は、=とLIKEの両方を使用できます。
この場合、「=」を使用すると少し速くなります(完全一致を検索する)。SQLServer Management Studioで同じクエリを2回、「=」を使用して1回、「LIKE」を1回使用して確認できます。次に、「クエリ」/「実際の実行計画を含める」を使用します。
2つのクエリを実行すると、結果が2回表示され、さらに2つの実際の実行計画が表示されます。私の場合、それらは50%対50%に分割されていましたが、 "="実行計画では "推定サブツリーコスト"が小さくなります(一番左の "SELECT"ボックスの上にカーソルを置くと表示されます)。大きな違いではありません。
ただし、LIKE式でワイルドカードを使用して検索を開始すると、検索パフォーマンスが低下します。検索 "LIKE Mill%"はまだかなり高速です - SQL Serverはその列にインデックスがあればそれを使用できます。 SQL Serverがこの検索を満たす唯一の方法は全表スキャンを実行することであるため、 "LIKE%expression%"の検索は非常に遅くなります。だからあなたのLIKEには気をつけて!
マーク
パフォーマンスに関する元々の問題に対処するために、インデックス使用率になります。単純なテーブルスキャンが発生すると、 "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
"=" vs "LIKE"を使用した場合、クエリプランの作成にも無視できるほどの違いがあるかもしれません。
ワイルドカード以外に、=
と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
を使用する=
とVARCHAR
の両方でスペースが重要になりますが、CHAR
では使用できません( documentation 参照)。
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キーワードには間違いなく「performance price-tag」が付いています。そうは言っても、あなたのクエリで使われるワイルドカード文字を含む可能性のある入力フィールドがあるなら、LIKEを使うことをお勧めします ワイルドカードの1つを含む場合のみ 。そうでなければ、比較と等しい標準を使用してください。
宜しくお願いします...
本当にそれはあなたがクエリに何をさせたいのかにかかっています。完全に一致する場合は、=を使用してください。あいまい一致を意味する場合は、LIKEを使用してください。あなたが言っていることを言うのは、通常、コードを使った良い方針です。
Oracleでは、ワイルドカードを含まない「like」は「equals」と同じ結果を返しますが、追加の処理が必要になる可能性があります。 Tom Kyte氏によると 、リテラルを使用する場合、Oracleはワイルドカードを使用しない「like」を「equals」として扱いますが、バインド変数を使用するときは扱いません。
=
とLIKE
は同じではありません。
=
は正確な文字列と一致しますLIKE
は、ワイルドカード(%)を含む可能性があるストリングと一致します