Equals(=) vs. LIKE

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

如果没有任何特殊操作符,LIKE=是相同的,对吗?

390467 次浏览

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

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

在90年代翻白眼

我也怀疑它有点慢,但如果模式中没有通配符,我怀疑它的意义。

=LIKE是不一样的;

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

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

实际上,这取决于您希望查询做什么。如果你的意思是精确匹配,那么使用=。如果你的意思是一个模糊匹配,那么使用LIKE。对代码来说,表达自己的意思通常是一个很好的策略。

取决于数据库系统。

通常没有特殊字符,是的,=和LIKE是一样的。

但是,某些数据库系统可能会对不同的操作符使用不同的排序设置。

例如,在MySQL中,字符串上的=默认情况下总是不区分大小写的,所以没有特殊字符的LIKE是一样的。在其他一些RDBMS上,LIKE是不区分大小写的,而=则不是。

LIKE=是不同的。LIKE是你在搜索查询中使用的。它还允许像_(简单字符通配符)和%(多字符通配符)这样的通配符。

如果你想要精确匹配,应该使用=,它会更快。

这个站点解释了LIKE .

如果要搜索精确匹配,可以同时使用,=和LIKE。

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

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

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

马克

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

最好的祝福……

equals(=)操作符是一个“比较操作符,比较两个值是否相等”。换句话说,在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”开头的任何结果。

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

不同的运营商

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的字符长度不等于该长度 ,则较短的字符串有效 为便于比较,已替换为 它本身即被延伸到越长的长度 串在一个或多个衬垫的右边 字符,其中填充字符是基于CS选择的。如果 CS有NO PAD属性,那么PAD字符是一个 与任何实现相关的字符都不同 X和Y字符集中排序较少的字符 而不是CS下的任何字符串。否则,填充字符为a & lt; space> . < / p > b) X和Y比较的结果由 排序序列CS.

c)根据排序顺序,两个字符串可以 比较为相等,即使它们的长度或长度不同 包含不同的字符序列。当操作 MAX、MIN、DISTINCT、对分组列的引用,以及 UNION,除,和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如何比较字符串:

& lt; predicate>

M LIKE P

如果存在将M划分为子字符串的分区,则为真 这样:< / p >

i) M的子字符串是0个或多个连续的序列 M和每个字符的字符表示 representation>

ii)如果p的第i个子字符串说明符是任意的 字符说明符,M的第i个子字符串是任意一个 & lt;字符representation> . < / p >

iii)如果p的第i个子字符串说明符是任意字符串 说明符,则M的第i个子串为的任意序列 0个或更多的<字符表示>s

iv)如果p的第i个子字符串说明符不是 任意字符说明符或任意字符串说明符, 那么M的第i个子串就等于这个子串 的排序顺序 <类谓语>,不加<空格> 字符到M,并且与该子字符串的长度相同 说明符。< /强> < / p >

v) M的子串的个数等于

(强调)。

这太啰嗦了,让我们分解一下。第ii和iii项分别指通配符_%。如果P不包含任何通配符,则只有第iv项适用。这是OP提出的感兴趣的情况。

在本例中,它比较每个“;子字符串”;(单个字符)对应于M中的每个子字符串,使用当前排序规则。

结论

底线是在比较字符串时,=比较整个字符串,而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

当使用"="和"LIKE"时,在查询计划的创建中也可能存在可以忽略不计的差异。

在Oracle中,不带通配符的“like”将返回与“equals”相同的结果,但可能需要额外的处理。汤姆·凯特报道, Oracle在使用文字时将不带通配符的“like”视为“equals”,但在使用绑定变量时则不会。

除了通配符,=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不会,无论是CHAR还是VARCHAR

  • 使用PostgreSQL 9.1时,空格对于=和使用VARCHARLIKE都是有效的,但对于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"的行

对于这个例子,我们想当然地认为varcharcol不包含'',并且在这一列上没有空单元格

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

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

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

这是我对问题SQL & # 39;像# 39;vs & # 39; = & # 39;性能的另一个答案的复制/粘贴:

一个使用mysql 5.5的个人例子:我在2个表之间有一个内部连接,一个是300万行,一个是1万行。

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

where login like '12345678'

使用'explain'我得到:

enter image description here

当对同一个查询使用'='时,大约需要0.1秒:

where login ='12345678'

使用“explain”我得到:

enter image description here

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

=LIKE快得多。

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

SELECT * FROM XXXXX WHERE f_time = '1621442261' -花费0.00s并返回330条记录

SELECT * FROM XXXXX WHERE f_time like '1621442261' -花了44.71秒,返回330条记录