究其所以然(二)为什么隐式类型转换会导致索引失效

628 阅读2分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

前言

上一节,我们简单说了下mysql的索引,以及为什么like ‘%xx’会导致索引失效。总结来说就是一句话,‘%xx’破坏了索引值的有序性,因此优化器就决定放弃走树搜索功能。今天我们来探讨一下索引失效的另外一个原因,隐式类型转换。来一起究其所以然吧!

隐式类型转换

顾名思义,当两个类型不同的值进行比较时,需要转换成相同类型。而这一操作是mysql优化器来做的,所以被称之为隐式类型转换。那就又一个问题了,字符串和数字比较,到底是都转成字符串比较还是转成数字比较呢?咱们来实践一下。
image.png
同是数字类型相比较,结果是1。那如果‘10’>9或者10>‘9’的结果是都是1,则可以证明字符串和数字比较会把字符串转换成数字来比较。咱们实践证明一下。

image.png

image.png
实践证明真理,mysql的转换规则是,字符串转换成数字

回归问题本身

image.png 先看例子,这张表的user_id是varchar类型的,所以建的索引也是字符串类型的。我们分别实践一下用字符串查询和数字查询的explain结果。 image.png 可以看出当用user_id = 123查询时,是全表扫描的。用上面说的mysql转换规则很好解释,user_id和123比较时,会先将user_id进行类型转换成数字在和123比较。等同于是
CAST(user_id AS signed int) = 123
代表在索引字段上做了函数操作,和like一样破坏了索引值的有序性,优化器自然不会选择走树索引功能。 那反过来呢?索引是int类型的,查询条件是字符串,会走索引么?我们来看phone这个字段的例子。 image.png 上面的例子理解的话,这个很好解释的。因为发生类型转换的不是索引字段,而是查询条件。相当于
phone = CAST('9898' AS signed int) 这样看是不是清晰很多,没有对索引字段做函数操作,自然是成功走索引的。

总结

like也好,函数操作也好,类型转换也好,导致索引失效的本质之一是破坏了索引值的有序性。所以大家在写sql的时候多用explain,总会有一些意外的发现!