会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 什么?MySQL的等值查询竟然出错了?!

什么?MySQL的等值查询竟然出错了?

时间:2025-11-05 13:46:19 来源:益强数据堂 作者:应用开发 阅读:648次

1.问题背景

前段时间,值查一个业务线的询竟小伙伴大G找过来,如下是然出我俩的对话。

大G:云杰,值查听说你MySQL挺厉害的询竟,我最近遇到一个奇怪问题,然出不知道你遇到过没,值查请教你下。询竟

我:请教不敢当,然出我也就是值查个MySQL入门级选手,说来看看。询竟

大G:WHERE条件去等值查询字符串,然出结果却查出来几条尾部有空格的值查,明明不相等。询竟

我:不会吧?然出这么神奇,这个真没遇到过!

大G:不信你试试!

我:试试就试试!

抱着求知的心态,开启了本篇的探索之旅。

2.验证

2.1 数据准备

首先在测试库里建表,并准备相关的原数据。创建个user_info表,分别插入adu(无空格)、adu (一个空格)、源码库adu    (四个空格)三个用户。

复制CREATE TABLE `user_info`

(

`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 主键自增ID

,

`user_name` VARCHAR(64) NOT NULL DEFAULT COMMENT 名字

,

PRIMARY KEY (`id`

),

KEY `idx_user_name` (`user_name`

)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=用户表

;

INSERT INTO user_info(user_name) values(adu); #无空格INSERT INTO user_info(user_name) values(adu ); #一个空格INSERT INTO user_info(user_name) values(adu ); #四个空格1.2.3.4.5.6.7.8.9.10.11. 2.2 问题验证

2.2.1 尾部空格验证

复制SELECT * FROM user_info WHERE user_name = adu; #无空格SELECT * FROM user_info WHERE user_name = adu ; #一个空格SELECT * FROM user_info WHERE user_name = adu ; #两个空格SELECT * FROM user_info WHERE user_name = adu ; #四个空格1.2.3.4.

我们使用如上条件去查,还真复现了!无论查询中尾部带有几个空格,结果是一样的,都会命中adu、adu 、adu    三个用户,结果如下图所示(红框圈起来的表示我们认为不应该出现的异常结果):

太神奇了!

2.2.2 头部空格验证

那如果把空格放在前面呢?再来一把,结果如下:这下又匹配不上了。空格放在后边可以,放在前边不可以,这太神奇了!!

2.2.3 唯一索引验证

那如果在user_name字段上建唯一索引,还能插入这三条记录吗?再来一把,结果如下:

也不行,被唯一索引约束住了。

2.2.4 长度验证

那这三条记录的user_name长度又分别是多少呢?

确实长度也不一样。

2.3 验证小结

从结果上来看,明明是三个长度不同的字符串,空格放在前边被认为是不同,放在后边又被认为是云服务器相同,而且唯一索引也冲突。我们有充足的理由怀疑MySQL忽略字符串尾部的空格,把adu、adu 、adu    都当成adu来处理。这确实超出了已有的认知,那背后的原因究竟又是什么呢?

3.分析原因

查询MySQL的官方文档[1],原来跟字符串的校对规则有关。

原来MySQL的校对规则基于PAD SPACE,这就意味着CHAR、VARCHAR、TEXT等字符串的等值比较(“=”)会忽略掉尾部的空格,而且官网也说了,适用于所有MySQL版本,并且不会改变。这。。。

既然MySQL官网说的这么肯定,那么自信来自哪里呢?我们继续追查SQL规范,原来SQL规范还真对这块做了特别说明[2],亿华云如下所示:

既然规范都这样要求了,等值查询“=”不能精确查询,那么到底该如何精确地进行等值查询呢?

4.精确查询的方法

通过调研,我们可以通过以下两种方式进行精确等值查询。

4.1 LIKE

LIKE是基于逐个字符进行比较的,这样就不会忽略尾部的空格,官网对这块也有特别的说明。

那么我们再使用LIKE进行等值查询,结果还真可以!

4.2 BINARY

BINARY不是函数,是类型转换运算符,它用来强制它后面的字符串转为二进制字节,再逐个字节比较,也可以理解成精确匹配,官网[4]对这块也有特别的说明。

那么我们再使用BINARY进行等值查询,结果也是可以的。

5.总结

MySQL的CHAR、VARCHAR、TEXT等字符串字段在等值比较("=")时,基于PAD SPACE校对规则,会忽略掉尾部的空格;在存储时,不会自动截断尾部的空格,会按原值存储;如果想要精确查询就不能用等值查询("="),而应改用LIKE或BINARY;认知有界,而求知无界。

关于作者

杜云杰,高级架构师,转转架构部负责人,转转技术委员会执行主席,腾讯云TVP。负责服务治理、MQ、云平台、APM、IM、分布式调用链路追踪、监控系统、配置中心、分布式任务调度平台、分布式ID生成器、分布式锁等基础组件。

道阻且长,拥抱变化;而困而知,且勉且行。

(责任编辑:系统运维)

推荐内容
  • VMware,虚拟系统之王,以前介绍过,见博文:诡异的虚拟机大师——VMware,VMware的强悍之处很多,其中之一就是可以轻松在虚拟和现实中穿梭,当然要实现这一愿望,就得安装VMware Tools了,呵呵,有些人可以不知道怎么安装呢,尤其LINUX下的安装,今天偶就把偶的安装过程和大家分享一下,呵呵,有不当之处,还请斧正 WIN系统操作系统一向追求易用为上,所以呀,安装VMware Tools也是一件非常轻松简单的事情,看截图吧(以最新推出的WIN2008测试版为例,其他像XP、VISTA都一样)  弹出对话框,确认是否安装,这不是废话嘛,当然要安装了  一会,VMware Tools的安装文件就被加载到系统的光驱中并自动运行安装程序了 WIN系统操作系统的一大毛病,需要重启,重启后状态栏显示为安装成功就一切OK了   和WIN2008时的虚拟机状态栏显示的一样 和WIN2008仍然是一样  也可以加载到光驱中,可不能自动安装了,这就是LINUX的一大缺点,易用性太差 UBUNTU自带的新立得安装管理器也不好使,看来只能手动命令行安装了  UBUNTU的命令行窗口就是“附件”里的“终端”,好奇怪的名字 13.jpg: 这是比关键的步骤啦,依次输入以下命令: --------------------------该行不输入 $sudo apt-get install build-essential --------------------------该行不输入 后面一路回答Y或回车就OK了 好了,安装到此结束,可以享受穿梭于真实与虚拟的快感了
  • 原来不只是fastjson,这个你每天都在用的类库也被爆过反序列化漏洞!
  • 使用 gosec 检查 Go 代码中的安全问题
  • MySQL数据库性能的提高,并不难
  • 小米电脑系统重新安装教程(以小米电脑重新做系统的步骤和注意事项)
  • 国王的秘密:如何保护你的主密码