0%

Mysql 索引系列(五):覆盖索引

覆盖索引并不是一种索引类型,也不是索引结构,只能算是一种索引策略。

什么是覆盖索引

覆盖索引:SQL只需要通过索引就可以返回查询所需要的数据,而不必通过二级索引查到主键之后再去查询数据。

首先要了解覆盖索引之前,你必须要了解什么是聚簇索引和非聚簇索引,还有一个必须要了解的就是回表,覆盖索引其实就是跟到底需不需要回表有直接的关系的。

什么是回表呢?
通俗的讲就是,如果索引的列在 select 所需获得的列中或者根据一次索引查询就能获得记录就不需要回表,如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。只有非聚簇索引是需要回表的,所以如果你懂得非聚簇索引的存储的结构,你自然就知道为啥需要回表了。

为什么需要覆盖索引

举例我们建了一张学生表,其中包含字段id设置主键索引、name设置普通索引、age(无处理),并向数据库中插入 4 条数据:

  • (”小赵”, 10)
  • (”小王”, 11)
  • (”小李”, 12)
  • (”小陈”, 13)
1
2
3
4
5
6
7
8
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`name` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '名称',
`age` int(3) unsigned NOT NULL DEFAULT '1' COMMENT '年龄',
PRIMARY KEY (`id`),
KEY `I_name` (`name`)
) ENGINE=InnoDB;
INSERT INTO student (name, age) VALUES("小赵", 10),("小王", 11),("小李", 12),("小陈", 13);

这里我们设置了主键为自增,那么此时数据库里数据为:

id name age
1 小赵 10
2 小王 11
3 小李 12
4 小陈 13

每一个索引在 InnoDB 里面对应一棵B+树,那么此时就存着两棵B+树。

索引结构

可以发现区别在与叶子节点中,主键索引存储了整行数据,而非主键索引中存储的值为主键id, 在我们执行如下sql后:

SELECT age FROM student WHERE name = ‘小李’;

流程为:

  • 在 name 索引树上找到名称为小李的节点 id 为03
  • 从 id 索引树上找到id为 03 的节点 获取所有数据
  • 从数据中获取字段命为 age 的值返回 12

在流程中从非主键索引树搜索回到主键索引树搜索的过程称为:回表,在本次查询中因为查询结果只存在主键索引树中,我们必须回表才能查询到结果;

如何优化,不需要回表呢?

以name和age两个字段建立联合索引,sql命令与建立后的索引树结构如下:

ALTER TABLE student ADD INDEX I_name_age(name, age);

联合索引

那在我们再次执行如下sql后:

SELECT age FROM student WHERE name = ‘小李’;

流程为:

  • 在name,age联合索引树上找到名称为小李的节点
  • 此时节点索引里包含信息age 直接返回 12

此时不再需要回表

总结

覆盖索引即从非主键索引中就能查到的记录,而不需要查询主键索引中的记录,避免了回表的产生减少了树的搜索次数,显著提升性能。覆盖索引并不是一种索引类型,而是一种建索引的策略。

参考资料

MySQL 覆盖索引详解