name like '%林'
方式来查询,因为查询的结果可能是「陈林、张林、周林」等之类的,所以不知道从哪个索引值开始比较,于是就只能通过全表扫描的方式来查询 。想要更详细了解 InnoDB 的 B+ 树查询过程,可以看我写的这篇:B+ 树里的节点里存放的是什么呢?查询数据的过程又是怎样的?
对索引使用函数有时候我们会用一些 MySQL 自带的函数来得到我们想要的结果,这时候要注意了,如果查询条件中对索引字段使用函数,就会导致索引失效 。
比如下面这条语句查询条件中对 name 字段使用了 LENGTH 函数,执行计划中的 type=ALL,代表了全表扫描:
// name 为二级索引select * from t_user where length(name)=6;

文章插图
为什么对索引使用函数,就无法走索引了呢?【MySQL 索引失效-模糊查询,最左匹配原则,OR条件等。】因为索引保存的是索引字段的原始值,而不是经过函数计算后的值,自然就没办法走索引了 。
不过,从 MySQL 8.0 开始,索引特性增加了函数索引,即可以针对函数计算后的值建立一个索引,也就是说该索引的值是函数计算后的值,所以就可以通过扫描索引来查询数据 。
举个例子,我通过下面这条语句,对 length(name) 的计算结果建立一个名为 idx_name_length 的索引 。
alter table t_user add key idx_name_length ((length(name)));
然后我再用下面这条查询语句,这时候就会走索引了 。
文章插图
对索引进行表达式计算在查询条件中对索引进行表达式计算,也是无法走索引的 。
比如,下面这条查询语句,执行计划中 type = ALL,说明是通过全表扫描的方式查询数据的:
explain select * from t_user where id + 1 = 10;

文章插图
但是,如果把查询语句的条件改成 where id= 10 - 1,这样就不是在索引字段进行表达式计算了,于是就可以走索引查询了 。

文章插图
为什么对索引进行表达式计算,就无法走索引了呢?原因跟对索引使用函数差不多 。
因为索引保存的是索引字段的原始值,而不是 id + 1 表达式计算后的值,所以无法走索引,只能通过把索引字段的取值都取出来,然后依次进行表达式的计算来进行条件判断,因此采用的就是全表扫描的方式 。
有的同学可能会说,这种对索引进行简单的表达式计算,在代码特殊处理下,应该是可以做到索引扫描的,比方将id + 1 = 10 变成 id= 10 - 1 。
是的,是能够实现,但是 MySQL 还是偷了这个懒,没有实现 。
我的想法是,可能也是因为,表达式计算的情况多种多样,每种都要考虑的话,代码可能会很臃肿,所以干脆将这种索引失效的场景告诉程序员,让程序员自己保证在查询条件中不要对索引进行表达式计算 。
对索引隐式类型转换如果索引字段是字符串类型,但是在条件查询中,输入的参数是整型的话,你会在执行计划的结果发现这条语句会走全表扫描 。
我在原本的 t_user 表增加了 phone 字段,是二级索引且类型是 varchar 。
然后我在条件查询中,用整型作为输入参数,此时执行计划中 type = ALL,所以是通过全表扫描来查询数据的 。
经验总结扩展阅读
- MySQL 全局锁、表级锁、行级锁,你搞清楚了吗?
- golang中的nil接收器
- llinux下mysql建库、新建用户、用户授权、修改用户密码
- RedHat7.6安装mysql8步骤
- golang中的字符串
- flutter系列之:flutter中可以建索引的栈布局IndexedStack
- 究极无敌细节版 Mysql索引
- Mysql通过Canal同步Elasticsearch
- MySQL的日志文件
- 01-MySQL8主从详解