前些天有个同事说他数据库查询性能很差,对查询的列加了索引还是很慢。我一看他的表结构和代码转换出的查询语句,大概知道是什么问题 — 出现了隐式类型转换。当我们对不同类型的值进行比较时,MySQL 为了让这些不同类型的值可比较,就会对它们进行类型转换。通过 MySQL 文档 我们可以查看有哪些情况会出现类型转换。最常见的情况就是 一个字符类型的列在查询的时候我们传递了一个数字,举个例子,建张表,随便灌几十万数据进去:



CREATE



比如我们做一个简单的查询:



SELECT * FROM implicit_conv where num_str = 1000002



发现性能确实很差,explain 一下发现建好的索引确实没用上:




mysql转换科学计数法 mysql转换成数字_mysql查询前转换为数字


SELECT * FROM implicit_conv where num_str = '1000002'


将 1000002 改为字符串 '1000002' 发现性能上来了,explain 一下发现索引用上了:


mysql转换科学计数法 mysql转换成数字_mysql查询前转换为数字_02


隐式类型转换除了会带来性能问题,还可能带来安全问题,也可能对你的业务造成意料之外的结果:比如你插入一条 num_str 为 01000002abc 的数据,你再次查询,结果就不对了:


mysql转换科学计数法 mysql转换成数字_隐式类型转换_03


原因就是和文档中提到的,这个时候发生隐式类型转换,将 1000002 和 num_str 列中的值都转换为浮点类型的进行比较,01000002abc 转换为浮点类型的和 1000002的结果一样,所以都被查询出来了。

如果你插入的值不是 01000002abc 而是 01000002 那就更危险了,你在对 1000002 记录更新或删除时,可能将其它的记录也一并更新或删除了:


mysql转换科学计数法 mysql转换成数字_隐式类型转换_04


我们这里还有一个对比的例子,就是 str_num 列,这是 int 类型的,这个不管我们是用数字来查询还是用字符串来查询都能使用到索引:


mysql转换科学计数法 mysql转换成数字_隐式类型转换_05


为什么都用上索引呢?这个难道没发生隐式类型转换吗?当然也发生了,文档里也说了;这里还能使用索引就是因为 int 转换为浮点类型结果是一样的,所以还能用索引。查询没性能问题但是还是一样存储业务问题的,你查询的是 0100050 但 100050 这条结果被查询出来了:


mysql转换科学计数法 mysql转换成数字_mysql查询前转换为数字_06


所以我们在日常工作中一定要小心隐式类型转换。避免出现一些“感觉不可思议“ 的问题。