1.查询中使用了函数

比如一个具有创建时间的表,记录了从16年到18年的记录,如果查询所有的6月份的数据,并且使用了函数,比如如下的sql

select count(*) from tradelog where month(t_modified) = 6

那么是无法使用索引的

因为将数据记录在索引树上的形式为

图片

只是传入了一个月份的函数,但是开头是年份,MySql是无法快速定位到准确数据的

对一些索引做函数操作,可能会导致破坏了索引有序性,并且决定不走树的搜索功能

但是查看Explain命令,发现这个Sql语句的执行为

图片

尝试使用了t_modified这个索引,但是没有成功,仍然扫描了整个表

如果改为如下的语句,可以将其索引利用起来,但是要求知道对应的年份

select count(*)  from tradelog where (create_time >=’2016-7-1′ and  create_time<=’2016-7-30′ )or (create_time >= ‘2017-7-1’ and create_time <= ‘2017-7-30’) or (create_time >= ‘2018-7-1’ and create_time <= ‘2018-7-30’)

同理,如下的计算方式也不能使用索引

select * from tardelog where id+1 = 10000,并不能直接使用id索引,必须改为

select * from tradelog where id = 10000-1;才可行

2.sql语句中有隐式的类型转换

比如一个表的主键id为varchar类型,但是输入了一个整型,这就需要隐式的类型转换

类型转换变慢的原因很好理解,就是使用了字符串转为数字的函数

select * from tradelog where tradeid = 100117;

其实就是

select * from tradelog where CAST(tradid as singed int) = 110111;

相当于还是使用了函数导致不走搜索树功能

3.字符集的转换

假设有两行表,一个两个表的字符集不一致,一个是utf-8,一个是utf8mb4

这样,需要进行两个表的联查的时候,可能触发以下的情况

比如如下的联查语句

mysql> select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2; /*语句Q1*/

发现执行计划不对

图片

关于第一个id =2的查询,只是扫描了一行

关于联查的时候,则是进行了全表扫描

至于,为何出现了这个问题,可以看如下的执行流程

图片

根据tradeId到trade_detail表中查询匹配的行的时候,没有使用索引,这是因为一个表的字符集为utf-8,一个的字符集为utf-8mb4

导致了数据的隐式转换

实际上的语句就是

mysql> select * from trade_detail where COUVERT(tradeid USING utf8mb4)=$L2.tradeid.value;

这就是问题所在

如果翻转一下sql语句的查询呢?

mysql>select l.operator from tradelog l , trade_detail d where d.tradeid=l.tradeid and d.id=4;

会发现就查询了短短的几行

我们依旧看一下表的拆解

select operator from tradelog  where traideid =$R4.tradeid.value;

实际上转换的CONVERT函数加载了对应的输入参数上,避免了全表搜索

总体来说,对于无法使用索引的常见问题,都与函数操作有关

发表评论

邮箱地址不会被公开。 必填项已用*标注