等于(=)与 LIKE

Posted

技术标签:

【中文标题】等于(=)与 LIKE【英文标题】:Equals(=) vs. LIKE 【发布时间】:2010-10-07 07:31:06 【问题描述】:

使用 SQL 时,在 WHERE 子句中使用 = 代替 LIKE 有什么好处吗?

如果没有任何特殊的运算符,LIKE= 是一样的,对吧?

【问题讨论】:

可能要指定数据库类型... mssql、mysql、oracle? 您的问题至少有5 对like-operator 标签的投票。能否请您将sql-like 推荐为synonym? @FreshPrinceOfSO,当我获得足够的声誉时,我会这样做。谢谢。 【参考方案1】:

不同的运算符

LIKE= 是不同的运算符。这里的大多数答案都集中在通配符支持上,这不是这些运算符之间的唯一区别!

= 是一个对数字和字符串进行操作的比较运算符。比较字符串时,比较运算符比较整个字符串

LIKE 是一个字符串运算符,逐个字符地进行比较

更复杂的是,两个运算符都使用collation,这可能会对比较结果产生重要影响。

激励例子

让我们首先确定一个示例,其中这些运算符产生明显不同的结果。请允许我引用 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 Standard § 8.2 描述了= 如何比较字符串:

两个字符串的比较判断如下:

a) 如果 X 的字符长度不等于长度 在 Y 的字符中,则较短的字符串有效 为了比较的目的,替换为 本身已经延伸到更长的长度 在一个或多个焊盘的右侧连接字符串 字符,其中填充字符是根据 CS 选择的。如果 CS 有 NO PAD 属性,那么填充字符是 与任何不同的实现相关的字符 X 和 Y 的字符集中整理较少的字符 比CS下的任何字符串。否则,填充字符是 。

b) X 和 Y 的比较结果由下式给出 整理序列 CS。

c) 根据整理顺序,两个字符串可能 比较相等,即使它们的长度不同或 包含不同的字符序列。当操作 MAX、MIN、DISTINCT、对分组列的引用以及 UNION、EXCEPT 和 INTERSECT 运算符指代字符 字符串,这些操作从中选择的特定值 一组这样的相等值取决于实现。

(已添加重点。)

这是什么意思?这意味着在比较字符串时,= 运算符只是当前排序规则的一个薄包装。排序规则是具有用于比较字符串的各种规则的库。以下是a binary collation from 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 collation,它支持不区分大小写的比较。代码太长,无法粘贴到此处,但请转到该链接并阅读my_strnncollsp_utf8mb4() 的正文。此排序规则一次可以处理多个字节,并且可以应用各种转换(例如不区分大小写的比较)。 = 操作符完全从变幻莫测的排序规则中抽象出来。

LIKE 是如何工作的?

SQL Standard § 8.5 描述了LIKE 如何比较字符串:

M LIKE P

如果存在将 M 划分为子字符串的情况,则为真 这样:

i) M 的子串是 0 个或多个连续的序列 M的和每个恰好是一个子字符串的一部分。

ii) 如果 P 的第 i 个子串说明符是任意的 字符说明符,M 的第 i 个子串是任意单个 .

iii) 如果 P 的第 i 个子字符串说明符是任意字符串 说明符,则 M 的第 i 个子串是 0 个或多个 s。

iv) 如果 P 的第 i 个子字符串说明符既不是 任意字符说明符或任意字符串说明符, 那么 M 的第 i 个子串等于那个子串 说明符根据整理顺序 ,不附加 字符到 M,并且具有与该子字符串相同的长度 说明符。

v) M 的子串数等于 P 的子串说明符。

(已添加重点。)

这很罗嗦,所以让我们分解一下。项 ii 和 iii 分别指通配符 _%。如果P 不包含任何通配符,则仅适用第iv 项。这是 OP 提出的感兴趣的案例。

在这种情况下,它使用当前排序规则将M 中的每个“子字符串”(单个字符)与P 中的每个子字符串进行比较。

结论

底线是在比较字符串时,= 比较整个字符串,而LIKE 一次比较一个字符。两种比较都使用当前排序规则。这种差异在某些情况下会导致不同的结果,如本文的第一个示例所示。

你应该使用哪一个?没有人能告诉你——你需要使用适合你用例的那个。不要通过切换比较运算符过早地进行优化。

【讨论】:

“EQUALS 逐字节比较两条数据”:过于简单化,而且往往不正确,因为可以使用 COLLATE 修改 EQUALS (=) 行为,从而导致比较字符类而不是字符。例如。请参阅 dev.mysql.com/doc/refman/5.0/en/charset-collate.html (MySQL) 或 sqlmag.com/blog/forcing-collation-where-clause-22-jun-2011 (SQL Server)。 @mehase 这不可能是真的。如果我的 varchar 字段包含值 'AbCdEfG',并且我执行了 WHERE MyCol = 'abcdefg',我仍然会返回该行,即使它们显然不是逐字节等效的 PeterB 和@Kip 都提出了优点。我改进了我的答案,试图解释排序规则如何影响这些运算符。 这似乎不再正确:set charset latin1;SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;gives 0 和 SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;gives 0。 因此,如果查询搜索来自表单,可能包含也可能不包含通配符,最好在字符串中搜索通配符并构建查询字符串,而不是默认为 LIKE? 【参考方案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”开头的任何内容。

希望对您有所帮助。可以在here 找到一些有用的信息。

【讨论】:

我的印象是 OP 知道何时使用 LIKE 以及何时使用 =,他只是想知道在没有通配符的情况下是否存在性能差异。这个答案简要介绍了这一点,但我觉得这个答案的 95% 并不真正相关。 非常正确。我不确定我回答时问题是否相同。如果是这样,我确实错过了询问性能的部分。感谢您的观察。 这个答案很糟糕。 LIKE 和 '=' 是完全不同的运算符,但恰好在一些小部分情况下表现相似。为了子孙后代,请阅读此处的其余回复,或者至少在您将其记住之前在谷歌搜索“mysql like”。 另一方面,这个答案回答了我在谷歌上搜索的问题。有时,如果答案能回答问题的标题和内容一样好。 在使用 char 和 varchar2 时要记住一个很好的想法。如果将 char 与 char 进行比较。在比较数据库之前,首先将第一个“变量”的长度转换为与第二个相同的长度。如果您比较 char 和 varchar2 数据库将什么也不做。 docs.oracle.com/cd/A64702_01/doc/server.805/a58236/c_char.htm【参考方案3】:

这是我对问题SQL 'like' vs '=' performance的另一个答案的复制/粘贴:

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

当在如下索引上使用like时(没有通配符),大约需要30秒:

where login like '12345678'

使用“解释”我得到:

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

where login ='12345678'

使用“解释”我得到:

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

【讨论】:

有趣,感谢您使用高填充表公开结果,解释和考虑索引,这也非常有用 @suarsenegger 是的,大桌子改变了一切【参考方案4】:

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

如果你想要完全匹配,应该使用=,这样会更快。

This site explains LIKE

【讨论】:

【参考方案5】:

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

【讨论】:

虽然这适用于 MySQL 和 MS SQL,但不适用于 PostgreSQL。【参考方案6】:

取决于数据库系统。

一般不用特殊字符,是的,=和LIKE是一样的。

但是,某些数据库系统可能会因不同的运算符而以不同的方式处理排序规则设置。

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

【讨论】:

这个奇怪的东西有没有类似概述的东西?【参考方案7】:

对于这个例子,我们认为 varcharcol 不包含 '' 并且该列没有空单元格是理所当然的

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

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

like - 由于其目的,它的工作速度稍慢,旨在用于 varchar 和类似数据。

【讨论】:

【参考方案8】:

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

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

执行这两个查询,您应该会看到两次结果以及两个实际的执行计划。在我的例子中,它们被分成 50% 和 50%,但是“=”执行计划的“估计子树成本”更小(当您将鼠标悬停在最左边的“SELECT”框上时显示)——但同样,它真的差别不大。

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

马克

【讨论】:

-1 否,它并不总是快一点。如果使用 %mystring% 对列进行索引,则速度会慢几个数量级。事实上,任何称职的代码标准都将有严格的指导方针,说明何时以及何时不应该在比 micky 鼠标数据库更大的数据库上使用类似的东西。 我从来没有说过在所有情况下它都会慢一点 - 我说如果你搜索一个精确匹配它会慢一点。当然,使用 LIKE 和使用通配符进行搜索,尤其是在搜索项的开头和结尾处,会慢得多,这一点毫无疑问。 是的,我同意——一个应该对何时使用 LIKE 有明确的指导方针(仅当您需要使用通配符进行搜索时)。但是话又说回来-理论上,理论和实践之间没有区别,但是在实践中.......【参考方案9】:

在运行时构建查询时,使用 = 可避免字符串中出现通配符和特殊字符冲突。

这使得程序员的生活变得更轻松,因为不必转义所有可能滑入 LIKE 子句并且不会产生预期结果的特殊通配符。毕竟,= 是 99% 的用例场景,每次都要逃避它们会很痛苦。

在 90 年代翻白眼

我也怀疑它有点慢,但如果模式中没有通配符,我怀疑它是否重要。

【讨论】:

【参考方案10】:

要解决有关性能的原始问题,归结为索引利用率。当发生简单的表扫描时,“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”时,查询计划的创建也可能存在微不足道的差异。

【讨论】:

【参考方案11】:

除了通配符之外,=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,在比较中将忽略尾随空格,但当列类型为VARCHAR 时,LIKE 除外。

使用MySQL 5.5,= 的尾随空格将被忽略,但LIKE 的尾随空格将被忽略,CHARVARCHAR 均如此。

使用PostgreSQL 9.1,空格在=LIKE 使用VARCHAR 时都很重要,但对于CHAR 则不重要(请参阅documentation)。

LIKE 的行为也与 CHAR 不同。

使用与上述相同的数据,在列名称also makes a difference 上使用显式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”的行。

【讨论】:

【参考方案12】:

实际上,这取决于您希望查询做什么。如果您的意思是完全匹配,请使用 =。如果您的意思是模糊匹配,请使用 LIKE。说出你的意思通常是一个很好的代码策略。

【讨论】:

【参考方案13】:

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

最好的问候...

【讨论】:

【参考方案14】:

在 Oracle 中,不带通配符的“like”将返回与“equals”相同的结果,但可能需要额外处理。 According to Tom Kyte,Oracle 将在使用文字时将不带通配符的“like”视为“equals”,但在使用绑定变量时不会。

【讨论】:

【参考方案15】:

=LIKE 快得多。

在 11GB 数据和超过 1000 万条记录的 MySQL 上测试,f_time 列被索引。

SELECT * FROM XXXXX WHERE f_time = '1621442261' - 耗时 0.00 秒并返回 330 条记录

SELECT * FROM XXXXX WHERE f_time like '1621442261' - 耗时 44.71 秒并返回 330 条记录

【讨论】:

【参考方案16】:

=LIKE不一样;

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

【讨论】:

它可以不使用通配符。问题询问相同情况的差异。 = 不完全匹配。 'x' = 'x'

以上是关于等于(=)与 LIKE的主要内容,如果未能解决你的问题,请参考以下文章

在oracle数据库中有时候like加上not like 的数据却不等于总行数为啥

mybatis : trim标签, “等于==”经验, CDATA标签 ,模糊查询CONCAT,LIKE

MySQL WHERE LIKE 语句:如何删除表中列子字符串不等于所需子字符串的行?

Hive 内建操作符与函数开发——深入浅出学Hive

mybatis plus条件拼接

LIKE查询与实体框架[重复]