跳到主要内容

聚集索引 VS 非聚集索引

聚集索引 VS 非聚集索引

在 MySQL 中,B+树索引按照存储方式的不同分为聚集索引和非聚集索引。(有些地方又称非聚集索引为二级索引)

提示

聚集索引就是主键索引,非聚集索引就是普通索引

数据库中的 B+ 树索引可以分为聚集索引(clustered index)和辅助索引(secondary index),但是不管是聚集还是辅助的索引,其内部都是 B+ 树的,即高度平衡的,叶子节点存放着所有的数据。

聚集索引与辅助索引不同的是,叶子节点存放的是否是一整行的信息。

示例:建表

create table T(
id int primary key,
k int not null,
name varchar(16),
index (k)
) engine = InnoDB;

id 字段是聚簇索引,k 字段是普通索引(二级索引)

非聚集索引与聚集索引的区别在于 非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。

  • 如果语句是 select * from T where ID = 500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
  • 如果语句是 select * from T where k = 5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。

由于 InnoDB 存储引擎表是索引组织表,因此 InnoDB 存储引擎的辅助索引的书签就是相应行数据的聚集索引键。图 5-15 显示了 InnoDB 存储引擎中辅助索引与聚集索引的关系。

辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引来找到一个完整的行记录。

其实可以理解聚簇索引和非聚簇索引的区别为:聚簇索引是将数据行存储在叶子节点,而非聚簇索引则是将索引值和指向数据行的指针存储在叶子节点。

  1. 主键一定是聚簇索引(在 InnoDB 中),但“聚簇索引”并不一定必须是主键。

    • 如果表没有主键,InnoDB 会选择一个唯一的非空唯一索引作为聚簇索引。
    • 如果也没有唯一索引,它会隐式生成一个 rowid 来做聚簇索引。
  2. 一个表 只能有一个聚簇索引

    • 因为数据的物理存储只能按照一种顺序来排序。
    • 其他非主键索引叫做 二级索引(secondary index),它们叶子节点存的不是数据行本身,而是对应的“聚簇索引键”。
  3. 在其他数据库里情况不同:

    • SQL Server 里主键默认会建立聚簇索引,但可以改为非聚簇索引。
    • Oracle 并没有显式的聚簇索引概念(有索引组织表 IOT)。

下面可以看到两种索引的物理结构区别

关键差异:

  • 聚簇索引:叶子节点存储完整的行数据
  • 非聚簇索引:叶子节点存储索引列值 + 主键值(用于回表)

联合索引是什么?

后面要学习的最左前缀匹配原则:在 MySQL 建立联合索引时会遵守最左前缀匹配原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。

要想理解联合索引的最左匹配原则,先来理解下索引的底层原理。索引的底层是一颗 B+ 树,那么联合索引的底层也就是一颗 B+ 树,只不过联合索引的 B+ 树节点中存储的是键值。由于构建一棵 B+ 树只能根据一个值来确定索引关系,所以数据库依赖联合索引最左的字段来构建。

举例:创建一个(a,b)的联合索引,那么它的索引树就是下图的样子。

可以看到 a 的值是有顺序的,1,1,2,2,3,3,而 b 的值是没有顺序的 1,2,1,4,1,2。

但是我们又可发现 a 在等值的情况下,b 值又是按顺序排列的,但是这种顺序是相对的。这是因为 MySQL 创建联合索引的规则是首先会对联合索引的最左边第一个字段排序,在第一个字段的排序基础上,然后在对第二个字段进行排序。

所以 b = 2 这种查询条件没有办法利用索引。