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属性がある場合、パッド文字は、XとYの文字セット内のどの文字とも異なる実装依存の文字であり、CSの下のどのストリングよりも照合が少なくなります。それ以外の場合、埋め込み文字はです。
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 predicate>の照合シーケンスに従って、その部分文字列指定子と等しくなります。 Mへの<space>文字の追加。その部分文字列指定子と同じ長さ。
v)Mの部分文字列の数は、Pの部分文字列指定子の数と同じです。
(強調が追加されました。)
これはかなり冗長なので、分解してみましょう。項目iiとiiiは、それぞれワイルドカード_
とを参照してい%
ます。P
ワイルドカードが含まれていない場合、アイテムivのみが適用されます。これは、OPによって提起された関心のあるケースです。
この場合、現在の照合を使用M
しP
て、各 "部分文字列"(個々の文字)を各部分文字列と比較します。
一番下の行は、=
文字列をLIKE
比較するときに、一度に1 文字を比較しながら文字列全体を比較することです。どちらの比較でも現在の照合が使用されます。この違いは、この投稿の最初の例で証明されているように、場合によっては異なる結果になります。
あなたはどちらを使うべきですか?誰もそれを伝えることはできません—あなたのユースケースに合ったものを使う必要があります。比較演算子を切り替えることによって時期尚早に最適化しないでください。
LIKE
いますが、この答えは、withing またはpresent を使用するLIKE
ことはを使用することとまったく同じではないことを驚くほど説明しています。あなたの答えが千の賛成票を受け取るかもしれません。%
_
=
'AbCdEfG'
、と私はWHERE MyCol = 'abcdefg'
、私はまだ彼らは明確ではないバイトごと同等であっても、その行を取り戻す
set charset latin1;
SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
0をSELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
与え、0も与えます。
等号(=)演算子は、「比較演算子が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"で始まるすべての結果を返します。
お役に立てば幸いです。いくつかの良い情報がここにあります。
これは、SQLの「like」と「=」のパフォーマンスの質問に対する私の別の回答のコピー/貼り付けです。
mysql 5.5を使用した個人的な例:300万行の1つと1万行の1つの2つのテーブル間に内部結合がありました。
以下のように(ワイルドカードなしで)インデックスにいいね!を使用すると、約30秒かかりました:
where login like '12345678'
私が得る「説明」を使用して:
同じクエリで「=」を使用すると、約0.1秒かかりました。
where login ='12345678'
私が得る「説明」を使用して:
ご覧のlike
ように、インデックスシークは完全にキャンセルされたため、クエリに300倍の時間がかかりました。
LIKE
と=
は異なります。LIKE
検索クエリで使用するものです。_
(単純な文字のワイルドカード)や%
(複数文字のワイルドカード)などのワイルドカードも使用できます。
=
完全一致が必要な場合に使用してください。
この例では、varcharcolに''
この列に対する空のセルが含まれておらず、セルがないことは当然のことと考えています
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
最初のものは0行の出力になり、2番目のものはリスト全体を表示します。=は厳密に一致するケースですが、likeはフィルターのように機能します。フィルターに基準がない場合、すべてのデータが有効です。
のような-その目的のために少し遅く動作し、varcharおよび同様のデータでの使用を目的としています。
完全一致を検索する場合は、=とLIKEの両方を使用できます。
この場合、「=」を使用すると少し高速になります(完全一致の検索)。SQLServer Management Studioで同じクエリを2回使用して、「=」を1回、「LIKE」を1回使用して、これを自分で確認できます。次に、「クエリ」/「実際の実行プランを含める」を使用します。
2つのクエリを実行すると、結果が2回表示され、さらに2つの実際の実行プランが表示されます。私の場合、それらは50%対50%に分割されましたが、「=」実行プランの方が「推定サブツリーコスト」が小さくなっています(左端の「SELECT」ボックスにカーソルを合わせると表示されます)。大きな違いではありません。
ただし、LIKE式でワイルドカードを使用して検索を開始すると、検索パフォーマンスが低下します。"LIKE Mill%"を検索すると、かなり高速になる可能性があります。SQLServerは、その列にインデックスがあれば、それを使用できます。"LIKE%expression%"の検索は、SQL Serverがこの検索を満たす唯一の方法が全テーブルスキャンを実行することであるため、恐ろしく遅くなります。したがって、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
また、「=」と「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
使用して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」の行のみを返します。
Oracleでは、ワイルドカードのない「like」は「equals」と同じ結果を返しますが、追加の処理が必要になる場合があります。Tom Kyte氏によれば、Oracleは、ワイルドカードのない「like」をリテラルの使用時に「等しい」として扱いますが、バインド変数の使用時は扱いません。