当前位置: 首页 > 科技观察

什么?MySQL的等价查询是错误的?

时间:2023-03-13 18:12:56 科技观察

1。问题背景前段时间,一个叫大G的商业小伙伴找到我。以下是我们的对话。大G:云杰,听说你MySQL很厉害。我最近遇到一个奇怪的问题。不知道你有没有遇到过。请帮我。我:不敢求教,我只是一个入门级的MySQL玩家,一起来看看吧。大G:使用WHERE条件查找等价的查询字符串,结果发现有几个字符串末尾有空格,明显不相等。我:不会吧?太神奇了,我以前从未见过!大G:不信你试试!我:试试吧!怀着求知的心态,我开始了本文的探索之旅。2.验证2.1数据准备首先在测试库中建表,准备相关原始数据。创建一个user_info表并插入三个用户'adu'(无空格)、'adu'(一个空格)和'adu'(四个空格)。CREATETABLE`user_info`(`id`BIGINT(20)UNSIGNEDNOTNULLAUTO_INCREMENTCOMMENT'主键自增ID',`user_name`VARCHAR(64)NOTNULLDEFAULT''COMMENT'name',PRIMARYKEY(`id`),KEY`idx_user_name`(`user_name`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='usertable';插入user_info(user_name)values('adu');#没有空格INSERTINTOuser_info(user_name)values('adu');#一个空格INSERTINTOuser_info(user_name)values('adu');#四个空格2.2问题验证2.2.1尾随空格验证SELECT*FROMuser_infoWHEREuser_name='adu';#没有空格SELECT*FROMuser_infoWHEREuser_name='adu';#onespaceSELECT*FROMuser_infoWHEREuser_name='adu';#两个空格SELECT*FROMuser_infoWHEREuser_name='adu';#four空格我们用上面的条件来检查,真的很复杂啦!不管查询末尾的空格有多少,结果都是一样的,都会命中'adu','adu','adu'三个用户,结果如下图(红框表示我们认为不应该出现异常结果):Amazing!2.2.2headspaceverification如果空格放在前面怎么办?再试一次,结果如下:这次又不匹配了。空格可以放在后面,但不能放在前面。这真太了不起了!!2.2.3唯一索引校验如果在user_name字段上建立唯一索引,这3条记录还能插入吗?再试一次,结果如下:也不行,被唯一索引约束了。2.2.4长度验证这三个记录的user_name的长度是多少?长短确实不一样。2.3验证小结从结果来看,很明显存在三个不同长度的字符串。空格放在前面算不一样,放在后面算一样,唯一索引也冲突。我们有充分的理由怀疑MySQL忽略了字符串末尾的空格,并将'adu'、'adu'和'adu'视为'adu'。这确实超出了现有的认知,那么背后的原因是什么呢?3、分析原因查询MySQL官方文档[1],原来是与字符串的校对规则有关。原来MySQL的校对规则是基于PADSPACE的,也就是说CHAR、VARCHAR、TEXT等字符串的等价比较(“=”)会忽略尾部空格,官网也说适用于所有MySQL版本,并且不会改变。这。..既然MySQL官网这么肯定,那底气哪来的?我们继续跟踪SQL规范。原来SQL规范真的对这个做了专门的解释[2],如下图:既然规范这样要求,等值查询“=”是不能准确查询的,那么如何准确的做等值查询呢?4、精确查询的方法通过研究,我们可以通过以下两种方式进行精确等价查询。4.1LIKELIKE基于逐个字符的比较,因此尾部空格不会被忽略。官网对此也有专门说明。然后我们使用LIKE进行等价查询,结果真的很好!4.2BINARYBINARY不是函数,而是类型转换运算符。用于强制将其后面的字符串转换成二进制字节,然后逐字节进行比较,也可以理解为完全匹配。官网[4]对此也有专门的解释。然后我们用BINARY进行等值查询,结果也是可以的。5、综上所述,在MySQL的CHAR、VARCHAR、TEXT等字符串字段的等值比较(“=”)中,基于PADSPACE校对规则,尾部空格将被忽略;存储时,不会自动截断尾随空格。将按原值存储;如果要准确查询,不能使用等价查询(“=”),而应使用LIKE或BINARY;认知是有界的,而知识是无界的。作者简介杜云杰,资深架构师,转转架构部负责人,转转技术委员会执行主席,腾讯云TVP。负责服务治理、MQ、云平台、APM、IM、分布式调用链路跟踪、监控系统、配置中心、分布式任务调度平台、分布式ID生成器、分布式锁等基础组件。道阻且长,拥抱变化;知道自己何时陷入困境,并在鼓励下去做。