답변:
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 매뉴얼의이 페이지는 String Comparison Functions 이며, =
논의되지 않았으므로 이는 =
엄격하게 문자열 비교 함수가 아니라는 것을 의미 합니다.
=
작동합니까?SQL 표준 § 8.2 방법에 대해 설명 =
문자열을 비교 :
두 문자열의 비교는 다음과 같이 결정됩니다.
a) X 문자의 길이가 Y 문자의 길이와 같지 않으면 짧은 문자열은 비교를 위해 긴 문자열의 길이로 확장 된 자체 사본으로 효과적으로 대체됩니다. 하나 이상의 패드 문자의 오른쪽에 연결하여 패드 문자가 CS를 기준으로 선택됩니다. CS에 NO PAD 속성이있는 경우 패드 문자는 X 및 Y의 문자 세트에있는 문자와 다른 구현 종속 문자이며 CS의 문자열보다 작게 대조됩니다. 그렇지 않으면 패드 문자는입니다.
b) X와 Y의 비교 결과는 조합 순서 CS에 의해 주어진다.
c) 조합 순서에 따라 두 문자열은 길이가 다르거 나 다른 문자 시퀀스를 포함하더라도 동일하게 비교 될 수 있습니다. 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을 하위 문자열로 분할하는 경우 다음과 같습니다.
i) M의 서브 스트링은 M의 0 개 이상의 인접한 <문자 표현>의 시퀀스이며 M의 각 <문자 표현>은 정확히 하나의 서브 스트링의 일부입니다.
ii) P의 i 번째 서브 스트링 지정자가 임의의 문자 지정자 인 경우 M의 i 번째 서브 스트링은 임의의 단일 <문자 표현>입니다.
iii) P의 i 번째 서브 스트링 지정자가 임의의 스트링 지정자 인 경우, M의 i 번째 서브 스트링은 0 이상의 <문자 표현>의 임의의 시퀀스이다.
iv) P의 i 번째 서브 스트링 지정자가 임의의 문자 지정자 또는 임의의 스트링 지정자가 아닌 경우, M의 i 번째 서브 스트링은 <like predicate>의 조합 순서에 따라 해당 서브 스트링 지정자와 동일합니다. <space> 문자를 M에 추가하고 하위 문자열 지정자와 길이가 같습니다.
v) M의 서브 스트링 수는 P의 서브 스트링 지정자 수와 같습니다.
(공포도 추가됨)
이것은 꽤 말이 많으므로 세분화합시다. 항목 ii 및 iii은 각각 와일드 카드 _
및 %
을 나타냅니다. 경우 P
어떤 와일드 카드를 포함하지 않는, 만 항목 IV이 적용됩니다. 이것은 OP가 제기 한 관심사입니다.
이 경우 현재 데이터 정렬 M
을 P
사용하여 각 "하위 문자열"(개별 문자)을 각 하위 문자열과 비교합니다 .
결론은 =
문자열을 LIKE
비교할 때 한 번에 한 문자 를 비교 하면서 전체 문자열을 비교한다는 것입니다. 두 비교는 모두 현재 데이터 정렬을 사용합니다. 이 게시물의 첫 번째 예에서 알 수 있듯이이 차이는 경우에 따라 다른 결과로 이어집니다.
어느 것을 사용해야합니까? 아무도 당신에게 말할 수 없습니다. 사용 사례에 맞는 것을 사용해야합니다. 비교 연산자를 전환하여 조기에 최적화하지 마십시오.
LIKE
하지 않습니다,하지만이 답변이 놀랍 사용한다고 설명 LIKE
없이 %
또는 _
존재하는 것은 전혀 없습니다 사용하는 것과 같습니다 =
. 귀하의 답변에 수천 건의 찬성 투표를 받으십시오.
'AbCdEfG'
, 그리고 내가 WHERE MyCol = 'abcdefg'
, 나는 여전히 명확 바이트별로 동일하지 않더라도, 해당 행을 다시 얻을
set charset latin1;
SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
0을 제공하고 SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
도 0을 제공합니다.
equals (=) 연산자는 "비교 연산자가 두 값의 동등성을 비교합니다"입니다. 즉, SQL 문에서 방정식의 양변이 같지 않으면 참을 리턴하지 않습니다. 예를 들면 다음과 같습니다.
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 '='성능 에 대한 또 다른 대답의 복사 / 붙여 넣기입니다 .
mysql 5.5를 사용하는 개인 예제 : 2 개의 테이블, 3 백만 행 중 하나와 1 만 행 중 하나 사이에 내부 조인이있었습니다.
아래와 같이 (와일드 카드 없음) 인덱스에서 like를 사용할 때 약 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 행 출력이고 두 번째 결과는 전체 목록을 표시합니다. =는 필터와 같은 역할을하는 반면 엄격하게 일치하는 경우입니다. 필터에 기준이 없으면 모든 데이터가 유효합니다.
-그 목적으로 인해 조금 느리게 작동하며 varchar 및 유사한 데이터와 함께 사용하기위한 것입니다.
정확히 일치하는 항목을 검색하면 =와 LIKE를 모두 사용할 수 있습니다.
이 경우 "="를 사용하는 것이 조금 더 빠릅니다 (정확한 검색). SQL Server Management Studio에서 동일한 쿼리를 두 번, "="를 사용하여 한 번, "LIKE"를 사용하여 한 번, 그런 다음 "쿼리"/ "실제 실행 계획 포함"을 사용하십시오.
두 개의 쿼리를 실행하면 결과가 두 번 표시되고 두 개의 실제 실행 계획이 표시됩니다. 제 경우에는 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"를 사용할 때 쿼리 계획 작성에 무시할만한 차이가있을 수도 있습니다.
와일드 카드 외에 =
AND 의 차이점 LIKE
은 SQL Server 종류와 열 유형에 따라 다릅니다.
이 예제를 보자 :
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에 따르면 , 오라클은 리터럴을 사용할 때 와일드 카드가없는 '같은'을 '같음'으로 취급하지만 바인드 변수를 사용할 때는 그렇지 않습니다.