面试_mysql_聚簇索引和非聚簇索引

110 阅读2分钟

zhuanlan.zhihu.com/p/142139541



MySQL的InnoDB索引数据结构是B+树,主键索引叶子节点的值存储的就是MySQL的数据行,普通索引的叶子节点的值存储的是数据行指针,这是了解聚簇索引和非聚簇索引的前提。



什么是聚簇索引?

索引和数据存在一块,索引的value就是整个数据行,找到了索引就相当于找到了需要的数据。主键索引就是聚簇索引,相邻主键的数据放在相邻的物理存储位置上。



什么是非聚簇索引?

索引的存储和数据的存储是分离的,也就是说找到了索引但没找到数据,需要根据索引上的value(数据行指针)再次回表查询,非聚簇索引也叫做辅助索引。(Normal类型)





一个例子

下面我们创建了一个学生表,做三种查询,来说明什么情况下是聚簇索引,什么情况下不是。

create table student (
    id bigint,
    no varchar(20) ,
    name varchar(20) ,
    address varchar(20) ,
    PRIMARY KEY (`branch_id`) USING BTREE,
    UNIQUE KEY `idx_no` (`no`) USING BTREE
)ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

第一种,直接根据主键查询获取所有字段数据,此时主键是聚簇索引,因为主键对应的索引叶子节点存储了id=1的所有字段的值。

select * from student where id = 1


第二种,根据编号查询编号和名称,编号本身是一个唯一索引,但查询的列包含了学生编号和学生名称,当命中编号索引时,该索引的节点的数据存储的是主键ID,需要根据主键ID重新查询一次,所以这种查询下no不是聚簇索引

select no,name from student where no = 'test'


第三种,我们根据编号查询编号(有人会问知道编号了还要查询?要,你可能需要验证该编号在数据库中是否存在),这种查询命中编号索引时,直接返回编号,因为所需要的数据就是该索引,不需要回表查询,这种场景下no是覆盖索引

select no from student where no = 'test'



聚集索引一定比非聚集索引性能优么?

并不是。当SQL查询的列就是普通索引本身时,查询性能不输聚簇索引。




总结

  • 主键一定是聚簇索引,MySQL的InnoDB中一定有主键。MyISAM引擎没有聚簇索引。
  • 单表中只能有一个聚集索引,而非聚集索引单表可以存在多个。
  • 索引是通过多叉树的数据结构来描述的,我们可以这么理解:聚簇索引的叶节点就是数据节点;而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。