MySQL的隐式类型转换陷阱导致服务器频繁报警

SQL herman 221浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

气炸了,公众号又被举报了,心累。

那些举报我的小人,老子的世界不允许你的出现,带着你的虚伪滚出我的防线。

哎,气归气,生活还是要回归正常。

我给大家说一下,我日常的工作就是,写 bug,改 bug,背锅。这不昨天又背了一个锅。服务器突然就报警了,我一看有一条请求总是被超时。于是,这问题我得拿下。要不然那天爆发出一个大问题,这就不是背锅这么简单了,那是背铺盖卷儿走人了!虽然话有些严重,但是所有的事故都是由一个微小的举动引起的,我们不得不早早预防!

MySQL的隐式类型转换陷阱

我通过日志发现超时的这个接口很普通。实际上也就只有一个普通的查询语句,而且 SQL 还特简单。这句 SQL 我脱敏后,整理如下:

select * from xttblog where uid = '1314520';

其中,id 是一个 key,是一个 bigint 类型的 key。我拿着这种查询语句,执行上百遍都没有任何问题,但是在生产上就是会超时。

百思不得其解,有同事给我说,这条 SQL 他写错了,不应该带单引号的。我然后让他改,下次注意。但是,实际上加了单引号了也没问题,也可以查询。并且通过 explain 显示,并没有什么问题。

我知道有人会说,MySQL 在类型不匹配的时候,会放弃索引的。是的,大多数情况下你这样说是对的。但是,在我们今天这种情况下,你这样说就不对了。因为,上面的查询,是走索引的。那么问题出在哪里呢?原因是在 MySQL 中当字符串和数字比较时会把字符串转化为数字。如果是无法转换成数字的字符串都被转换成 0 来处理,也就是说无法转换成数字的字符串都会被转换成 0。

这样以来上面的语句,也就等价于下面的语句。

select * from xttblog where uid = 1314520;

既然是这样,哪为什么还会出现超时的情况呢?而且是经常出现?

于是,我去查了查 MySQL 的慢查询。发现有这样一条 SQL 语句,脱敏后 SQL 语句如下所示:

select * from xttblog where uid = '1314520xttblog';

我怎么说查询会超时,并且那个开发人员用字符串呢?搞半天传进来了这样的查询参数。其中项目上的漏洞,我先不说,我们今天就来说说这条 SQL 语句,为什么会超时呢?

根据《高性能 MySQL》中的内容显示,这条语句的执行过程是这样的。这个查询参数被 MySQL 截断了,原因是超过了 bigint 类型的长度。假设截断后是 1314520,那么 SQL 就拿这个 1314520 去匹配索引,因为是 select * 所以要回表。然后表中等于 1314520 的数据量非常的大,然后通过 1314520 查询到的数据从引擎层返回到 server 层,比较字符串后发现与 1314520xttblog 不相等,所以全部丢弃返回空。

MySQL 的这个“断章取义”真是害人不浅啊,蒙蔽了大家的双眼。另外我的设计也是有些问题的,这个我们以后再表。

MySQL 这个巨人现在也是非常落后了,AiSQL 和 MariaDb 都比它强。主要原因是 Oracle 才是亲儿子,这个捡的孩子不讨人喜欢!MySQL 的这种状态导致它的分支也一大堆,如果我们每个分支都学一下,学习成本要高出不少。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » MySQL的隐式类型转换陷阱导致服务器频繁报警