等于(=)与LIKE
在使用SQL时,在WHERE
子句中使用=
而不是LIKE
有什么好处?
没有任何特殊的操作符, LIKE
和=
是一样的,对吗?
不同的运营商
LIKE
和=
是不同的操作符。 这里的大部分答案都集中在通配符支持上,这不是这些操作符之间的唯一区别!
=
是对数字和string进行操作的比较运算符。 比较string时,比较运算符比较整个string 。
LIKE
是一个比较字符的string运算符 。
使问题复杂化的是,两个操作员都使用一个对比较结果有重要影响的sorting规则 。
激励的例子
我们首先找出这些运算符产生明显不同结果的例子。 请允许我引用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比较函数 ,并且=
没有被讨论,这意味着=
不是严格的string比较函数。
如何工作?
SQL标准§8.2描述了如何比较string:
两个string的比较如下确定:
a)如果X的字符长度不等于Y的字符长度,那么为了比较,较短的string被有效地replace为已经被扩展到较长string的长度的自身副本通过在一个或多个填充字符的右侧连接,其中基于CSselect填充字符。 如果CS具有NO PAD属性,则填充字符是一个与实现相关的字符,与X和Y字符集中的任何字符都不同,该字符集比CS下的任何string都less。 否则,填充字符是a。
b)X和Y的比较结果由整理顺序CS给出。
c)根据整理顺序,即使两个string长度不同,或者包含不同的字符序列,两个string也可能会相等。 当操作MAX,MIN,DISTINCT,对分组列的引用以及UNION,EXCEPT和INTERSECT运算符引用string时,这些操作从一组这样的相等值中select的具体值取决于实现。
(强调补充说。)
这是什么意思? 这意味着比较string时, =
运算符只是当前整理的一个简单的包装器。 sorting规则是一个具有各种比较string规则的库。 以下是MySQL的二进制sorting规则示例:
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); }
这种特定的sorting方式恰好是逐字节地比较(这就是为什么它被称为“二进制” – 它没有给string任何特殊的含义)。 其他sorting规则可能会提供更高级的比较。
例如,以下是支持不区分大小写的比较的UTF-8归类 。 代码太长,无法粘贴到此处,但请转到该链接并阅读my_strnncollsp_utf8mb4()
的正文。 此sorting规则可以一次处理多个字节,并且可以应用各种变换(如不区分大小写的比较)。 =
运算符完全从sorting的变幻莫测的抽象。
LIKE
如何工作的?
SQL标准§8.5描述了LIKE
如何比较string:
<谓词>
M LIKE P
如果存在将M划分为子string的情况,则:
i)M的子串是M的0个或更多个连续的<字符表示>的序列,M的每个<字符表示>是恰好一个子串的一部分。
ii)如果P的第i个子string说明符是任意字符说明符,则M的第i个子string是任何单个<字符表示>。
iii)如果P的第i个子string说明符是一个任意的string说明符,那么M的第i个子string是0或更多<字符表示>的任何序列。
iv)如果P的第i个子string说明符既不是任意的字符说明符也不是任意的string说明符,那么根据<like谓词>的整理顺序,M的第i个子string等于该子string说明符,而没有将<space>字符附加到M,并且具有与该子string说明符相同的长度。
v)M的子string的数量等于P的子string说明符的数量。
(强调补充说。)
这很罗嗦,所以让我们分解一下。 项目ii和iii分别指通配符_
和%
。 如果P
不包含任何通配符,则只有第iv项适用。 这是OP提出的兴趣。
在这种情况下,它使用当前归类比较M
中的每个“子串”(单个字符)与P
中的每个子串。
结论
底线是比较string时,比较整个string,而LIKE
比较一个字符。 两个比较都使用当前的sorting规则。 在某些情况下,这种差异会导致不同的结果,如本文后面的第一个例子所certificate的那样。
你应该使用哪一个? 没有人可以告诉你 – 你需要使用正确的用例。 不要通过切换比较操作员过早地进行优化。
等号(=)运算符是“比较运算符比较两个值是否相等”。 换句话说,在一个SQL语句中,除非等式两边相等,否则它不会返回true。 例如:
SELECT * FROM Store WHERE Quantity = 200;
LIKE运算符“实现模式匹配比较”,试图匹配“string值与包含通配符的模式string”。 例如:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKE通常只用于string,等于(我相信)更快。 等号运算符将通配符视为文字字符。 返回结果的差异如下:
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”开头的结果。
希望有所帮助。 一些很好的信息可以在这里find。
LIKE
和=
是不同的。 LIKE
是你会在search查询中使用的。 它也允许通配符,如_
(简单字符通配符)和%
(多字符通配符)。
=
应该使用,如果你想精确匹配,它会更快。
这个网站解释LIKE
这是我的另一个答案复制/粘贴问题SQL'像'vs'='performance :
一个使用mysql 5.5的个人示例:我有两个表之间的内部连接,300万行之一和10000行之一。
在下面的索引上使用类似的符号(没有通配符)时,大约需要30秒:
where login like '12345678'
使用'解释'我得到:
当在同一个查询中使用'='时,大约需要0.1秒:
where login ='12345678'
使用'解释'我得到:
正如你所看到的like
,索引查找完全取消了,所以查询花费了300多倍的时间。
一个区别 – 除了LIKE使用通配符的可能性之外 – 在尾部空格中:=运算符忽略尾随空格,但LIKE不会。
取决于数据库系统。
通常没有特殊字符,是的,=和LIKE是一样的。
但是,某些数据库系统可能会以不同的操作员不同的方式处理sorting规则设置。
例如,在MySQL中,比较= onstring默认情况下总是不区分大小写的,所以没有特殊字符的LIKE是相同的。 在其他一些RDBMS的LIKE是不区分大小写的,而=不是。
对于这个例子,我们认为varcharcol不包含''
并且对这个列没有空单元格
select * from some_table where varcharCol = '' select * from some_table where varcharCol like ''
第一个结果是0行输出,第二个显示整个列表。 =是严格匹配的情况,而像filter一样行为。 如果筛选器没有标准,则每个数据都是有效的。
像 – 由于其目的的工作原理慢一点,旨在用于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”时,查询计划的创build可能会有微不足道的差异。
在运行时构build查询时,使用=避免通配符和特殊字符在string中发生冲突。
这使得程序员的生活更轻松,无需转义LIKE子句中可能出现的所有特殊通配符,也不会产生预期的结果。 毕竟,=是99%的用例情况,每次都不得不逃脱它们是一件痛苦的事情。
在90年代卷眼睛
我也怀疑它有点慢,但是我怀疑这种模式中没有通配符是很重要的。
如果search完全匹配,则可以同时使用=和LIKE。
在这种情况下使用“=”要快一点(search完全匹配) – 您可以通过在SQL Server Management Studio中使用相同的查询两次,一次使用“=”,一次使用“LIKE”来检查然后使用“查询”/“包含实际执行计划”。
执行这两个查询,你应该看到你的结果两次,再加上两个实际的执行计划。 在我的情况下,他们分为50%和50%,但是“=”执行计划有一个较小的“估计的子树成本”(当你将鼠标hover在最左边的“select”框上时显示) – 但是,没有太大的差别。
但是,当您在LIKEexpression式中使用通配符开始search时,search性能会变暗。 search“LIKE Mill%”仍然可以相当快 – SQL Server可以使用该列上的索引(如果有的话)。 search“LIKE%expression式%”的速度非常慢,因为SQL Server可以满足这种search的唯一方法是通过全表扫描。 所以要小心你的LIKE!
渣子
除通配符之外, =
AND LIKE
之间的差异将取决于SQL服务器的types和列types。
以这个例子:
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 ,比较中将忽略尾随空格,但列types为
VARCHAR
时,LIKE
除外。 -
使用MySQL 5.5 ,尾部空格将被忽略
=
,而不是LIKE
,都使用CHAR
和VARCHAR
。 -
使用PostgreSQL 9.1 ,空间对于使用
VARCHAR
=
和LIKE
是很重要的,但对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关键字无疑附带了“性能价格标签”。 也就是说,如果你有一个可能包含通配符的input字段在查询中使用,那么只有当input包含一个通配符时,我才推荐使用LIKE。 否则,使用标准等于比较。
最好的祝福…
真的,这取决于你想要查询的内容。 如果你的意思是完全匹配,那么使用=。 如果你的意思是模糊的匹配,那么使用LIKE。 说出你的意思通常是一个很好的代码策略。
在Oracle中,没有通配符的“like”会返回与“equals”相同的结果,但可能需要额外的处理。 根据Tom Kyte的说法 ,Oracle在使用文字时不会将通配符视为“等号”,而是在使用绑定variables时不会使用通配符。
=
和LIKE
是不一样的;
-
=
匹配确切的string -
LIKE
匹配一个可能包含通配符(%)的string