我们来看看建立索引以后,这个表的组织结构图:
![为什么我使用了索引,查询还是慢?](http://img.jiangsulong.com/220410/1R00Q4J-5.jpg)
文章插图
这个语句的执行流程是这样的:
- 从索引上用树搜索,取到第1个age等于10的记录,得到它的主键id的值,根据id的值去主键索引取整行的信息,作为结果集的一部分返回;
- 在索引age上向右扫描,取下一个id的值,到主键索引上取整行信息,作为结果集的一部分返回;
- 重复上面的步骤,直到碰到第1个age大于15的记录;
对于一个大表,不止要有索引,索引的过滤性还要足够好 。
【为什么我使用了索引,查询还是慢?】像刚才这个例子的age,它的过滤性就不够好,在设计表结构的时候,我们要让所有的过滤性足够好,也就是区分度足够高 。
回表的代价那么过滤性好了,是不是表示查询的扫描行数就一定少呢?
我们再来看一个例子:
如果你的执行语句是 select * from t_people where name='张三' and age=8
t_people表上有一个索引是姓名和年龄的联合索引,那这个联合索引的过滤性应该不错,可以在联合索引上快速找到第1个姓名是张三,并且年龄是8的小朋友,当然这样的小朋友应该不多,因此向右扫描的行数很少,查询效率就很高 。
但是查询的过滤性和索引的过滤性可不一定是一样的,如果现在你的需求是查出所有名字的第1个字是张,并且年龄是8岁的所有小朋友,你的语句会怎么写呢?
你的语句要怎么写?很显然你会这么写:select * from t_people where name like '张%' and age=8;
在MySQL5.5和之前的版本中,这个语句的执行流程是这样的:
![为什么我使用了索引,查询还是慢?](http://img.jiangsulong.com/220410/1R00R1G-6.jpg)
文章插图
- 首先从联合索引上找到第1个年龄字段是张开头的记录,取出主键id,然后到主键索引树上,根据id取出整行的值;
- 判断年龄字段是否等于8,如果是就作为结果集的一行返回,如果不是就丢弃 。
- 在联合索引上向右遍历,并重复做回表和判断的逻辑,直到碰到联合索引树上名字的第1个字不是张的记录为止 。
你可以看到这个执行过程,它的回表次数特别多,性能不够好,有没有优化的方法呢?
在MySQL5.6版本,引入了index condition pushdown的优化 。我们来看看这个优化的执行流程:
![为什么我使用了索引,查询还是慢?](http://img.jiangsulong.com/220410/1R00U032-7.jpg)
文章插图
- 首先从联合索引树上,找到第1个年龄字段是张开头的记录,判断这个索引记录里面,年龄的值是不是8,如果是就回表,取出整行数据,作为结果集的一部分返回,如果不是就丢弃;
- 在联合索引树上,向右遍历,并判断年龄字段后,根据需要做回表,直到碰到联合索引树上名字的第1个字不是张的记录为止;
虚拟列可以看到这个优化的效果还是很不错的,但是这个优化还是没有绕开最左前缀原则的限制,因此在联合索引你还是要扫描8000万行,那有没有更进一步的优化方法呢?
我们可以考虑把名字的第一个字和age来做一个联合索引 。这里可以使用MySQL5.7引入的虚拟列来实现 。对应的修改表结构的SQL语句:
alter table t_people add name_first varchar(2) generated (left(name,1)),add index(name_first,age);
我们来看这个SQL语句的执行效果:CREATE TABLE `t_people`(`id` int(11) DEFAULT NULL,`name` varchar(20) DEFAUT NULL,`name_first` varchar(2) GENERATED ALWAYS AS (left(`name`,1)) VIRTUAL,KEY `name_first`(`name_first`,'age')) ENGINE=InnoDB DEFAULT CHARSET=utf8;
首先他在people上创建一个字段叫name_first的虚拟列,然后给name_first和age上创建一个联合索引,并且,让这个虚拟列的值总是等于name字段的前两个字节,虚拟列在插入数据的时候不能指定值,在更新的时候也不能主动修改,它的值会根据定义自动生成,在name字段修改的时候也会自动修改 。
推荐阅读
- 为什么微服务一定要有网关?
- 神仙下凡历劫是真的吗 为什么说1999年神仙下凡
- 为什么用携程买票买学生票的时候要付全价 携程上买学生票为什么是原价
- 大瑞铁路最新消息 大瑞铁路为什么那么难修
- 泰国为什么变性的多 泰国女妖是如何变成的
- 为什么你总是“想太多”?这个问题终于有答案了!
- 挂烫机喷一分钟蒸汽就不喷了是怎么了,挂烫机为什么只能喷几分钟就不喷了
- 车厘子为啥有点苦 车厘子看着很新鲜却为什么苦
- 为什么晚上不能照镜子梳头 新闻 为什么晚上不能照镜子梳头
- 你为什么总是画不好眼妆?新手必看的眼妆指南来了