前几天运维在群里发了一个线上慢sql日志的文档,在一个一个排查的过程中发现了一些以前没注意的问题。
其中一个sql是 select * from taobao_live_info a where a.live_id = 162356239345; 耗时5s
初看,我以为是live_id没加索引,以为这个明显是根据id去查,不可能慢的。看了表的索引信息,live_id 是有唯一索引的。这就让我匪夷所思了,虽然全表行数在160万, 但根据唯一索引查怎么可能慢呢? 我用explain 看了执行计划,结果如下:
type = ALL, 那肯定是全表扫描了!!
我怎么都想不出原因,直到我看了表结构之后,发现live_id 是 varchar类型,虽然业务上这个值是个数字,但这张表是从爬虫原始表同步过来的,爬虫那边为了最大程度兼容爬取的数据格式,一般都是用字符串格式。业务这边没有注意这个问题,而字段类型不匹配的话是不会走索引的!!
改了一下sql
select * from taobao_live_info a where a.live_id = '162356239345'
重新执行了explain, 结果是走索引了:
这个问题让我开始思考,项目中用的mybatis, 参数都是用的 #{}, 会自动在值加上' ', 这样,值都是字符串了,那其他地方不是都有问题?包括用id查询的地方,为什么以前没发现呢?
我重新对字段类型不匹配 的查询情况做了以下实验:
列是int, 用字符串匹配, 结果:走索引
列是字符串, 用数字匹配, 结果:不走索引
列是时间字符串, 用Date匹配, 结果:不走索引
列是Date, 用字符串匹配, 结果:走索引
可以看到,mysql有些情况是会自动转化格式的。当列是字符串,用其他类型匹配的时候,不会自动转化。