【MySQL】回表与索引优化-覆盖索引

一、索引分类

(一)MySQL 索引分类

数据结构:BTree索引、Hash索引; 应用层次:普通索引、唯一索引、复合索引、函数索引; 物理存储方式:聚簇索引和非聚簇索引。

(二)索引具体详解

普通索引:即一个索引只包含单个列,一个表可以有多个单列索引; 唯一索引:索引列的值必须唯一,但允许有空值; 复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并; 聚簇索引(聚集索引):并不是一种单独的索引类型,而是一种数据存储方式。具体细节取决于不同的实现,InnoDB的聚簇索引其实就是在同一个结构中保存了B+Tree索引和数据行,也就是InnoDB的主键索引; 非聚簇索引:除聚簇索引之外的就是非聚簇索引,也就是非主键索引也称二级索引或辅助索引;

对于主键索引和非主键索引,使用的数据结构都是 B+Tree,唯一的区别在于叶子结点中存储的内容不同:

  1. 主键索引的叶子结点存储的是一行完整的数据;
  2. 非主键索引的叶子结点存储的则是主键值,复合索引是主键和复合的字段。

二、回表

(一)主键查询

通过主键索引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 操作,所以查询部分字段可以使用覆盖索引来优化查询性能。

经验分享 程序员 微信小程序 职场和发展