使用SQL时,=
在WHERE
子句中使用而不是有什么好处LIKE
?
没有任何特殊的运营商,LIKE
并且=
是相同的,对不对?
使用SQL时,=
在WHERE
子句中使用而不是有什么好处LIKE
?
没有任何特殊的运营商,LIKE
并且=
是相同的,对不对?
Answers:
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描述了如何=
比较字符串:
确定两个字符串的比较如下:
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划分为子字符串的情况,则为true:
i)M的子字符串是M的0个或多个连续的<字符表示>的序列,M的每个<字符表示>都是一个子字符串的一部分。
ii)如果P的第i个子字符串说明符是任意字符说明符,则M的第i个子字符串说明符是任何单个<字符表示>。
iii)如果P的第i个子串说明符是任意字符串说明符,则M的第i个子串说明符是0或更多<字符表示>的任何序列。
iv)如果P的第i个子字符串说明符既不是任意字符说明符也不是任意的字符串说明符,则根据<like predicate>的整理顺序,M的第i个子字符串等于该子字符串说明符,而没有将<space>字符附加到M,并具有与该子字符串说明符相同的长度。
v)M的子串数量等于P的子串说明符数量。
(已添加重点。)
这很罗word,所以让我们分解一下。项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语句中,除非等式两边相等,否则它不会返回true。例如:
SELECT * FROM Store WHERE Quantity = 200;
LIKE运算符“实现模式匹配比较”,尝试将“字符串值与包含通配符的模式字符串进行匹配”。例如:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKE通常仅与字符串一起使用,而equals(我认为)更快。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”与“ =”性能的另一个答案的复制/粘贴:
一个使用mysql 5.5的个人示例:我在2个表之间进行了内部联接,其中300万行之一和1万行之一。
在以下索引上使用“赞”(不使用通配符)时,大约花费了30秒:
where login like '12345678'
使用“解释”,我得到:
在同一查询上使用'='时,大约需要0.1秒:
where login ='12345678'
使用“解释”,我得到:
如您所见,like
完全取消了索引查找,因此查询花费了300倍的时间。
如果搜索完全匹配,则可以同时使用=和LIKE。
在这种情况下,使用“ =”要快一点(搜索完全匹配)-您可以通过在SQL Server Management Studio中进行两次相同的查询来自己检查一下,一次使用“ =”,一次使用“ LIKE”,然后然后使用“查询” /“包括实际执行计划”。
执行两个查询,您应该看到两次结果,以及两个实际的执行计划。在我的情况下,它们的分配比例为50%与50%,但是“ =”执行计划的“估算子树成本”较小(当您将鼠标悬停在最左侧的“ SELECT”框上时显示)-但实际上没有太大的区别。
但是,当您开始使用LIKE表达式中的通配符进行搜索时,搜索性能会降低。搜索“ LIKE Mill%”仍然可以非常快-SQL Server可以在该列上使用索引(如果有的话)。搜索“ LIKE%expression%”的速度非常慢,因为SQL Server满足此搜索的唯一方法是执行全表扫描。因此,请小心您的喜欢!
渣
为了解决有关性能的原始问题,它归结为索引利用率。当进行简单的表扫描时,“ 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中,没有通配符的“喜欢”将返回与“等于”相同的结果,但可能需要进行其他处理。根据汤姆·凯特(Tom Kyte)的说法,在使用文字时,Oracle将不使用通配符的“类似”视为“等号”,而在使用绑定变量时则不会。