题
当使用SQL,是否有任何收益的使用 =
在一个 WHERE
条款,而不是的 LIKE
?
没有任何特别的经营者, LIKE
和 =
都是相同的,对吗?
解决方案
不同的运营商
和LIKE
是=
不同的运营商。这里大多数的答案集中在通配符支持,这是不是这些运营商之间的唯一区别!
=
是,在数字和字符串操作的比较运算符。当比较字符串,则比较操作符进行比较的整个字符串
LIKE
是比较逐字符
要复杂的是,无论是运营商使用归类一>其可具有在比较的结果产生重要影响。
激励实施例
让我们首先识别一个例子,其中这些运算符产生明显不同的结果。让我从MySQL手册引述如下:
每SQL标准,等执行匹配基于每个字符的基础上,从而它可以产生从=比较运算符不同的结果:
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操作符是指性格 串,从通过这些操作所选择的特定值 一组这样的相等值的是实现相关的。
(着重。)
这是什么意思?这意味着,在比较字符串时,该 这个特定比对情况比较逐字节(这就是为什么它被称为“二进制” - 它没有给出任何特殊含义的字符串)。其它归类可以提供更高级的比较。 例如,这里是一个 UTF-支持不区分大小写的比较核对8 。代码太长,贴在这里,只好到该链接,阅读 在 SQL标准§8.5 描述如何 在<谓词> 如果存在M的分割成子是真
使得: I)M的串是0或更多个连续的序列
<字符表示> M的S和各<字符
>的M个表示正好是一个子串的一部分。 ⅱ)如果P的第i子串符是任意
字符指定符,M的第i子串是任何单
<字符表示> ⅲ)如果P的第i子串说明符是任意字符串
符,则M的第i子串是任何序列
0或多个<字符表示>第 <强>ⅳ)如果P的第i子串符既不是
任意字符说明符,也不是任意的字符串说明,
然后M的第i子串等于串
根据所述排序序列符
在<像谓词>,而不的追加<空间>
字符M和具有相同的长度为子
说明符。强> v)的M的子串的数目等于的数
子串P的说明符。 (着重。) 这是很罗嗦,所以让我们把它分解。项II和III分别指的是通配符 在这种情况下,每个“子”(单个字符)在 在底线是比较字符串时, 哪一个?没有人能告诉你 - 你需要使用一个是为您的使用情况下是正确的。不要过早通过切换比较运营商优化。=
运营商仅仅是围绕当前归类的瘦包装。归类是具有用于比较字符串各种规则库。下面是href="https://github.com/mysql/mysql-server/blob/5.7/strings/ctype-bin.c"从MySQL rel="noreferrer">二进制排序
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);
}
my_strnncollsp_utf8mb4()
的身体。该核对可以一次处理多个字节,其可以应用各种变换(例如,不区分大小写的比较)。该=
运营商是完全抽象从核对变化无常。如何
LIKE
工作?LIKE
比较字符串:
M LIKE P
_
和%
。如果P
不包含任何通配符,那么只有第四项适用。这是由所构成OP利益的情况。M
使用当前归类比较针对每个子串在P
。结论
=
而LIKE
每次一个字符进行比较整个字符串进行比较。两个比较使用当前的排序规则。这种差别导致在某些情况下不同的结果,如在此后的第一个例子证明。
其他提示
在等于(=)运算符是一个“比较运算符的相等比较两个值”。换句话说,在一个SQL语句,它不会,除非等式的两边相等返回true。例如:
SELECT * FROM Store WHERE Quantity = 200;
LIKE运算符“实现了模式匹配的比较”试图匹配“针对含有通配符的模式字符串的字符串值。”例如:
SELECT * FROM Employees WHERE Name LIKE 'Chris%';
LIKE通常与串和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%';
将返回不同的结果,其中,使用“=”仅导致的结果与“克里斯%”被返回等操作者将返回任何开头“克里斯”。
希望有所帮助。一些好的信息可以发现这里。
这是用于“喜欢”问题 SQL矿的另一个答案的复制/粘贴VS '=' 效果:
使用个人例如MySQL的5.5:我有2个表,300万行之一和10000行之一之间的内部联接
。当使用像如以下(不含通配符)的索引,花了大约30秒:
where login like '12345678'
使用 '解释'我得到:
当使用一个“=”上的相同的查询,花了大约0.1秒时:
where login ='12345678'
使用 '说明' 我得到:
正如你所看到的,like
完全取消了索引查找,所以查询了300倍以上的时间。
一个差别 - 除了使用通配符与LIKE的可能性 - 是在尾部空格:=运算符忽略尾随的空间,但LIKE不
取决于数据库系统上。
一般来说,与没有特殊字符,是,=和LIKE是相同的。
一些数据库系统,但是,可以与不同的运营商不同地对待排序规则设置。
例如,在与对字符串= MySQL的比较是始终不区分大小写默认,所以像不含特殊字符是相同的。在某些其他RDBMS的LIKE是不区分大小写的同时=不
对于这个例子,我们认为理所当然的是varcharcol不含''
和具有针对该列没有空细胞
select * from some_table where varcharCol = ''
select * from some_table where varcharCol like ''
第一个结果在0行输出,而第二个示出的整个列表。 =是严格匹配的情况下,同时像像一个滤波器的行为。如果过滤器不具有的标准,每个数据是有效的。
像 - 通过它的目的凭借的作用有点慢,旨在与VARCHAR和类似的数据使用
如果您搜索完全匹配,则可以同时使用,=和LIKE。
使用“=”在这种情况下,一点点更快(搜索精确匹配) - 你可以有相同的查询两次在SQL Server Management Studio中,一旦使用“=”检查这个自己,一旦使用“LIKE ”,然后使用‘查询’/‘包括实际的执行计划。’
执行两个查询,你应该看到结果的两倍,再加上两个实际的执行计划。在我的情况,他们被分成50%和50%,但“=”执行计划有一个更小的“估计子树成本”(当你将鼠标悬停在最左边的“选择”框中显示) - 但是,它确实不是一个巨大的差异。
但是,当你开始在你的LIKE表达通配符搜索,搜索功能将dimish。搜索“LIKE穆勒%”仍然可以说是相当快 - SQL Server可以对列使用索引,如果有的话。搜索“LIKE%表达式%”是可怕的慢,因为只有这样,SQL Server可以满足这个搜索是做一个全表扫描。所以,要小心你的LIKE的!
马克
使用=当你建立在运行时查询避免通配符和一个特殊字符的冲突。
这使得程序员的生活因为不必逃避可能滑倒LIKE子句在不产生预期结果的所有特殊通配符容易。毕竟,=是99%的使用的情况下,这将是一个痛苦每次都逃脱它们。
在20世纪90年代辊眼睛
我也怀疑这是一个稍微慢一点,但我怀疑是否有模式没有通配符它显著。
要解决有关性能的原来的问题,它归结为索引利用率即可。当一个简单的表格的扫描发生时,“喜欢”和“=”是的相同强>。当索引参与,它的取决于如何形成LIKE子句即可。更具体而言,什么是通配符(S)?
的位置考虑如下:
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
将取决于两种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 Server2012年, 尾的空间将可忽略的进行比较,除了与
LIKE
当列类型VARCHAR
.使用 MySQL5.5, 尾的空间将被忽略
=
, 但不对LIKE
,两者都有CHAR
和VARCHAR
.使用 PostgreSQL9.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)
这只返回的行为"铸都"和"铸col".
LIKE关键字无疑都附带一“性能价格标签”。也就是说,如果你有一个输入字段可能包含通配符在查询中使用,我会建议使用例如仅输入中包含的外卡之一。否则,使用标准等于比较。
此致...
真的可以归结到你想要的查询做什么。如果你的意思是完全匹配,然后使用=。如果你的意思是一个模糊的匹配,然后使用等。说你的意思是通常与代码的好政策。
在Oracle中,“喜欢”,没有通配符将返回相同的结果作为“等于”,但可能需要额外的处理。 根据汤姆凯特,Oracle将使用绑定变量时治疗“喜欢”,没有通配符作为“等于”使用文字时,但不
=
和 LIKE
是不一样的;
=
匹配确切的字符串LIKE
匹配的一串可能包含符(%)