【MySQL】回表与索引优化-覆盖索引
一、索引分类
(一)MySQL 索引分类
数据结构:BTree索引、Hash索引; 应用层次:普通索引、唯一索引、复合索引、函数索引; 物理存储方式:聚簇索引和非聚簇索引。
(二)索引具体详解
普通索引:即一个索引只包含单个列,一个表可以有多个单列索引; 唯一索引:索引列的值必须唯一,但允许有空值; 复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并; 聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B+Tree索引和数据行,也就是InnoDB的主键索引; 非聚簇索引:除聚簇索引之外的就是非聚簇索引,也就是非主键索引也称二级索引或辅助索引;
对于主键索引和非主键索引,使用的数据结构都是 B+Tree,唯一的区别在于叶子结点中存储的内容不同:
- 主键索引的叶子结点存储的是一行完整的数据;
- 非主键索引的叶子结点存储的则是主键值,复合索引是主键和复合的字段。
二、回表
(一)主键查询
通过主键索引id来查询数据
select * from user where id=18
此时只需要搜索主键索引的 B+Tree 就可以找到数据,示意图如下:
(二)非主键查询
通过非主键索引来查询数据
select * from user where name=Alice
那么此时需要先搜索 name 这一列索引的 B+Tree,搜索完成后得到主键的值 然后再去搜索主键索引的 B+Tree,就可以获取到一行完整的数据
对于第二种查询方式而言,一共搜索了两棵 B+Tree,第一次搜索 B+Tree 拿到主键值后再去搜索主键索引的 B+Tree,这个过程就是所谓的回表。 从上面的分析中我们也能看出,通过非主键索引查询要扫描两棵 B+Tree,而通过主键索引查询只需要扫描一棵 B+Tree,所以如果条件允许,还是建议在查询中优先选择通过主键索引进行搜索。
(三)避免回表:覆盖索引
如果查询的列本身就存在于复合索引中,那么即使使用二级索引,一样也是不需要回表,即覆盖索引。 先来看查询回表的情况 创建两个单一的二级索引
alter table user add index index_name(name); alter table user add index index_age(age);
查看sql执行计划
explain select name,age from user where name = Alice;
查询到的Extra字段为空说明: 查询列存在未被索引覆盖、where筛选列是索引的前导列,意味着通过索引查找但通过“回表”来找到未被索引覆盖的字段。
再来看建立一个复合索引查询时不回表覆盖索引的情况
alter table user add index index_name_age(name,age);
查看sql执行计划
explain select name,age from user where name = Alice;
看查询到的Extra字段为Using index说明: 查询列被索引覆盖、where筛选列是索引的前导列 ,意味着通过索引查找就能直接找到符合条件的数据,并且无须回表,可以减少大量IO 操作,所以查询部分字段可以使用覆盖索引来优化查询性能。