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

如果没有特殊的操作员,LIKE=是一样的,对吗?

推荐答案

Different Operators

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

=是对数字和字符串进行操作的比较运算符.比较字符串时,比较运算符比较whole strings.

LIKE是比较character by character的字符串运算符.

更复杂的是,两个操作员都使用了collation,这可能会对比较结果产生重要影响.

Motivating Example

让我们首先确定一个例子,其中这些运算符产生明显不同的结果.请允许我引用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 Comparison Functions,这里没有讨论=,这意味着=严格来说不是一个字符串比较函数.

How Does = Work?

SQL Standard § 8.2描述了=如何比较字符串:

两个字符串的比较如下所示:

a) 如果X的字符长度不等于长度

b) The result of the comparison of X and Y is given by the collating sequence CS.

c) 根据排序顺序,可能会有两个字符串

(重点补充.)

这是什么意思?这意味着在比较字符串时,=运算符只是当前排序规则的一个薄包装.排序规则是一个具有各种比较字符串规则的库.以下是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()的正文.这种排序可以一次处理多个字节,并且可以应用各种转换(例如不区分大小写的比较).=运算符完全从排序规则的变幻莫测中抽象出来.

How Does LIKE Work?

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

这个<;谓词>;

M LIKE P

如果存在将M划分为子串的情况,则为真

i) M的子串是0或更多连续的序列

ii)如果P的第i子串说明符是任意的

iii)如果P的第i子字符串说明符是任意字符串

iv) If the i-th substring specifier of P is neither an arbitrary character specifier nor an arbitrary string specifier, then the i-th substring of M is equal to that substring specifier according to the collating sequence of the <like predicate>, without the appending of <space> characters to M, and has the same length as that substring specifier.

v) M的子串数等于

(重点补充.)

这很冗长,所以让我们把它分解一下.第二项和第三项分别指通配符_%.如果P不包含任何通配符,则仅第iv项适用.这是OP提出的有趣 case .

在本例中,它使用当前排序规则将M中的每个"子字符串"(单个字符)与P中的每个子字符串进行比较.

Conclusions

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

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

Sql相关问答推荐

Click house在数组中生成X行Y随机数

使用group by后我的平均输出不是我想要的

SQL查询以创建手头的流动余额?

获取家谱树中第一次出现的特定信息,然后停止

用相同值更新行

如何通过比较不同表中相同ID S的值来筛选ID为S的列表?

用于动态查询情况的存储过程常识模式

如何在Snowflake SQL存储过程中传递LIMIT和OFFSET的参数?

如何在presto/SQL中使用两个数组列创建(分解)单独的行

NULL-生成的列中连接的字符串的输入

数据库SQL-CTE命名空间(错误?)使用临时视图

postgres中的条件索引和触发器

通过UPDATE SELECT更新表时出现问题

将SQL Server查询改进为;线程安全;

清理 XML 数据

按公司和产品查询最近发票的平均价格的SQL查询

正则表达式:停在第一个匹配的其中一个字符位置上

如何通过CROSS APPLY获取多级嵌套JSON属性的值?

如何在 DAX 中通过 Window 函数应用订单

String_Split 多列