mysql引擎主要有两种实现方式,一种是B+树,一种是hash。而回表产生在B+树上(本文主要针对于innodb引擎来讲),这里还有一个内容:
1.聚簇索引 :叶子节点直接存放数据 (innodb)
2.非聚簇索引: 叶子节点存放的是数据的地址(myisam)
回表
在innodb中,如果采用主键进行查询则会直接访问到数据,也就是只需要进行一次查表
例:select * from student where id = ?
而如果采用二级索引(辅助索引)的情况则需要先使用二级索引查询到主键的值,再用主键查询来获取所需要的值,也就是回表。
回表会影响查询效率
例: select * from student where name = ?
使用该语句的情况下,会先根据二级索引(name)查询到值主键值(id),再根据id查询到对应数据
图片来源:https://zhuanlan.zhihu.com/p/29118331
索引覆盖
索引覆盖其实就是一种避免回表的方式,只需要在一棵索引树上就能获取SQL所需的所有列数据。
例:select id,name from student where name = '大哥'
在第一次使用二级索引时,就能够查询到对应的id值再加上自己本身的name值,左移只用在一颗索引树上做查询
那么在此基础上还想要查询到更多的值呢?
可以将被查询的字段建立到联合索引里去
例:
alter table student add index 'stu_ns_idx' (name,sex)
select id,name,sex from student where name = ?
索引下推
例 select * from student where name = ? and sex = ?
- 没有索引下推:
先从存储引擎中拉去数据(根据name筛选数据)
再mysql server 根据sex进行数据筛选
压力在服务器 - 有索引下推
会在拉取数据的时候直接根据name,sex来获取数据,不需要server做任何数据操作
压力在磁盘
索引下推唯一的缺点是需要再磁盘上做筛选,原来的筛选是放在内存的,现在放在了磁盘查找数据的环节,这样做看起来成本比较高,但是在数据库中所有数据都是排序的,所有的数据是聚集存放,所以性能不会有影响,而且整体io量会大大减少,反而会提升性能