等于(=)vs.喜欢


280

使用SQL时,=WHERE子句中使用而不是有什么好处LIKE

没有任何特殊的运营商,LIKE并且=是相同的,对不对?


4
可能想指定数据库类型... mssql,mysql,oracle?
艾伦·赖斯2009年

1
您的问题至少5like-operator标签具有投票权。我可以请您建议像sql这样同义词吗?
柯米特(Kermit)2013年

@FreshPrinceOfSO,当我获得足够的声誉时,我会这样做。谢谢。
特拉维斯

Answers:


270

不同的运营商

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比较一个字符。两种比较都使用当前的排序规则。如本文中的第一个示例所示,这种差异在某些情况下会导致不同的结果。

您应该使用哪一个?没有人能告诉您-您需要使用适合您的用例的一种。不要通过切换比较运算符来过早优化。


4
“ EQUALS逐字节比较两个数据”:过于简化,而且经常不正确,因为可以使用COLLATE修改EQUALS(=)行为,从而比较字符类而不是字符。例如,见dev.mysql.com/doc/refman/5.0/en/charset-collat​​e.html(MySQL的)或sqlmag.com/blog/forcing-collat​​ion-where-clause-22-jun-2011(SQL服务器)。
彼得B

11
是正确的答案。我们知道什么LIKE呢,但这个答案赫然解释说,使用LIKE没有%_存在是不是在所有与使用=。愿您的答案获得一千个投票。
rinogo 2014年

1
@mehase这不是真的。如果我的varchar字段包含value 'AbCdEfG',并且我这样做WHERE MyCol = 'abcdefg',即使它们显然不是逐字节等效的,我仍然会返回该行
Kip

1
PeterB和@Kip都提出了要点。我已经改进了答案,以尝试解释排序规则如何影响这些运算符。
Mark E. Haase

2
这似乎不再成立:set charset latin1; SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;给出0,也SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;给出0。
joanq

170

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”开头的任何内容。

希望能有所帮助。一些很好的信息可以在这里找到。


108
我的印象是,OP知道何时使用LIKE,何时使用=,他只是想知道当不存在通配符时是否存在性能差异。这个答案简短地涉及到了这个问题,但是我觉得这个答案的95%并没有真正的意义。
Outlaw程序员,

1
非常真实 我不确定回答时是否是相同的问题。如果是这样,我确实会错过询问性能的部分。感谢您的观察。
achinda99,2009年

9
这个答案很糟糕。LIKE和'='是完全不同的运算符,但是在少数情况下恰好表现类似。为了后代,请在将其提交到内存之前阅读此处的其余答复,或者至少在google上搜索“ mysql like”。
Mark E. Haase

3
另一方面,这个答案回答了我曾经提出过的问题,并在谷歌上寻找。有时,答案能回答问题的标题与内容一样好。
CorayThan

要记住的一个好想法是,当您使用char和varchar2时。如果将char与char比较。在比较数据库之前,首先将第一个“变量”的长度转换为第二个相同的长度。如果比较char和varchar2,数据库将不执行任何操作。 docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm
xild 2014年

18

这是我对问题SQL“ like”与“ =”性能的另一个答案的复制/粘贴:

一个使用mysql 5.5的个人示例:我在2个表之间进行了内部联接,其中300万行之一和1万行之一。

在以下索引上使用“赞”(不使用通配符)时,大约花费了30秒:

where login like '12345678'

使用“解释”,我得到:

在此处输入图片说明

在同一查询上使用'='时,大约需要0.1秒:

where login ='12345678'

使用“解释”,我得到:

在此处输入图片说明

如您所见,like完全取消了索引查找,因此查询花费了300倍的时间。


17

LIKE并且=是不同的。LIKE是您在搜索查询中使用的内容。它还允许使用通配符,例如_(简单字符通配符)和%(多字符通配符)。

= 如果您要完全匹配,则应使用,这样会更快。

本网站说明 LIKE


11

除了可以在LIKE中使用通配符之外,还有一个区别是尾随空格:=运算符忽略尾随空格,但LIKE不会。


4
虽然对于MySQL和MS SQL来说是正确的,但对于PostgreSQL则不是。
布鲁诺

10

取决于数据库系统。

通常,没有特殊字符,是的,=和LIKE相同。

但是,某些数据库系统可能对不同的运算符使用不同的排序规则设置。

例如,在MySQL中,在字符串上带有=的比较默认情况下始终不区分大小写,因此不带特殊字符的LIKE相同。在其他一些RDBMS上,LIKE不区分大小写,而=则不区分大小写。


对于这种奇怪情况,是否有类似概述的内容?
Gumbo

9

在此示例中,我们认为varcharcol不包含''并且在此列中没有空单元格是理所当然的

select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''

第一个显示0行输出,第二个显示整个列表。=是严格匹配的情况,而like就像一个过滤器。如果过滤器没有条件,则每个数据均有效。

像-由于其目的而工作的速度稍慢,并且旨在与varchar和类似数据一起使用。


6

如果搜索完全匹配,则可以同时使用=和LIKE。

在这种情况下,使用“ =”要快一点(搜索完全匹配)-您可以通过在SQL Server Management Studio中进行两次相同的查询来自己检查一下,一次使用“ =”,一次使用“ LIKE”,然后然后使用“查询” /“包括实际执行计划”。

执行两个查询,您应该看到两次结果,以及两个实际的执行计划。在我的情况下,它们的分配比例为50%与50%,但是“ =”执行计划的“估算子树成本”较小(当您将鼠标悬停在最左侧的“ SELECT”框上时显示)-但实际上没有太大的区别。

但是,当您开始使用LIKE表达式中的通配符进行搜索时,搜索性能会降低。搜索“ LIKE Mill%”仍然可以非常快-SQL Server可以在该列上使用索引(如果有的话)。搜索“ LIKE%expression%”的速度非常慢,因为SQL Server满足此搜索的唯一方法是执行全表扫描。因此,请小心您的喜欢!


-1(不是),并不总是快一点。如果使用%mystring%为列建立索引,则速度要慢几个数量级。确实,任何值得花时间的代码标准都会对何时以及何时不使用严格的准则进行指导,就像在比鼠标鼠标数据库更大的数据库上一样。
Cruachan

1
我从来没有说过在所有情况下都会慢一点-我说如果您搜索完全匹配会慢一点。当然,使用LIKE进行搜索并使用通配符(尤其是在搜索项的开头和结尾)会慢得多,这毫无疑问。
marc_s

是的,我同意- 对于何时使用或不使用LIKE,应该有明确的指导原则(仅当您需要使用通配符进行搜索时)。但话又说回来-理论上,理论与实践之间没有区别,但是在实践中……
。– marc_s

6

使用=可以避免在运行时生成查询时字符串中的通配符和特殊字符冲突。

通过不必转义可能会滑入LIKE子句的所有特殊通配符并且不会产生预期的结果,这使程序员的工作更加轻松。毕竟,=是99%的用例场景,每次不得不逃避它们将是一件痛苦的事情。

上世纪90年代

我也怀疑它会慢一些,但是我怀疑模式中是否没有通配符是否有意义。


6

为了解决有关性能的原始问题,它归结为索引利用率。当进行简单的表扫描时,“ 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”时,查询计划的创建可能也可以忽略不计。


4

除通配符外,=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,都与CHARVARCHAR

  • 使用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”的行。


2

LIKE关键字无疑带有附加的“性能价格标签”。就是说,如果您的输入字段可能包含查询中要使用的通配符,那么我建议在输入包含其中一个通配符时才使用LIKE 。否则,使用等于标准的标准。

最好的祝福...


1

确实,这取决于您要查询执行的操作。如果您表示完全匹配,请使用=。如果您认为比赛比较模糊,请使用LIKE。说出您的意思通常是使用代码的好策略。


1

在Oracle中,没有通配符的“喜欢”将返回与“等于”相同的结果,但可能需要进行其他处理。根据汤姆·凯特Tom Kyte)的说法,在使用文字时,Oracle将不使用通配符的“类似”视为“等号”,而在使用绑定变量时则不会。


0

=而且LIKE不一样;

  1. = 匹配确切的字符串
  2. LIKE 匹配可能包含通配符(%)的字符串

2
不足答案

它可以不带通配符使用。问题询问了相同情况下的区别。
M-Razavi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.