隐式类型转换

99 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

和你分享一个经常让程序员掉坑里的例子,最近在我们实际项目当中也出现类似的错误。

SELECT 
       result_id
  FROM t_result force 
 WHERE task_result_id in(178815219420708864, 178815219370377216)

实际数据库id设置的字符类型,但是传入的参数是long类型

解决办法:

ALTER TABLE `t_result`  MODIFY COLUMN `result_id` BIGINT DEFAULT NULL COMMENT '结果id';

我们一起看一下这条 SQL 语句:

mysql> select * from tradelog where tradeid=110717;

交易编号 tradeid 这个字段上,本来就有索引,但是 explain 的结果却显示,这条语句需要走全表扫描。你可能也发现了,tradeid 的字段类型是 varchar(32),而输入的参数却是整型,所以需要做类型转换。

那么,现在这里就有两个问题:

  • 数据类型转换的规则是什么?

  • 为什么有数据类型转换,就需要走全索引扫描?

先来看第一个问题,你可能会说,数据库里面类型这么多,这种数据类型转换规则更多,我记不住,应该怎么办呢?

  • 如果规则是“将字符串转成数字”,那么就是做数字比较,结果应该是 1;

  • 如果规则是“将数字转成字符串”,那么就是做字符串比较,结果应该是 0。

验证结果如图 3 所示。

image.png

从图中可知,select “10” > 9 返回的是 1,所以你就能确认 MySQL 里的转换规则了:在 MySQL 中,字符串和数字做比较的话,是将字符串转换成数字。


mysql> select * from tradelog where tradeid=110717;

就知道对于优化器来说,这个语句相当于:


mysql> select * from tradelog where  CAST(tradid AS signed int) = 110717;

也就是说,这条语句触发了我们上面说到的规则:对索引字段做函数操作,优化器会放弃走树搜索功能。

现在,我留给你一个小问题,id 的类型是 int,如果执行下面这个语句,是否会导致全表扫描呢?


select * from tradelog where id="83126";

你可以先自己分析一下,再到数据库里面去验证确认。