vlambda博客
学习文章列表

详解mysql中聚集索引和非聚集索引

 

聚集索引 VS 非聚集索引

在 MySQL 中,B+ 树索引按照存储方式的不同分为聚集索引和非聚集索引。

这里我们着重介绍 InnoDB 中的聚集索引和非聚集索引:

聚集索引(聚簇索引):以 InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建主键,系统也会帮你创建一个隐式的主键。

这是因为 InnoDB 是把数据存放在 B+ 树中的,而 B+ 树的键值就是主键,在 B+ 树的叶子节点中,存储了表中所有的数据。

这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引

非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引

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

明白了聚集索引和非聚集索引的定义,我们应该明白这样一句话:数据即索引,索引即数据。

利用聚集索引和非聚集索引查找数据

前面我们讲解 B+ 树索引的时候并没有去说怎么在 B+ 树中进行数据的查找,主要就是因为还没有引出聚集索引和非聚集索引的概念。

下面我们通过讲解如何通过聚集索引以及非聚集索引查找数据表中数据的方式介绍一下 B+ 树索引查找数据方法。

利用聚集索引查找数据

还是这张 B+ 树索引图,现在我们应该知道这就是聚集索引,表中的数据存储在其中。

现在假设我们要查找 id>=18 并且 id<40 的用户数据。对应的 sql 语句为:

MySQL

1

select * from user where id>=18 and id <40

其中 id 为主键,具体的查找过程如下:

①一般根节点都是常驻内存的,也就是说页 1 已经在内存中了,此时不需要到磁盘中读取数据,直接从内存中读取即可。

从内存中读取到页 1,要查找这个 id>=18 and id <40 或者范围值,我们首先需要找到 id=18 的键值。

从页 1 中我们可以找到键值 18,此时我们需要根据指针 p2,定位到页 3。

②要从页 3 中查找数据,我们就需要拿着 p2 指针去磁盘中进行读取页 3。

从磁盘中读取页 3 后将页 3 放入内存中,然后进行查找,我们可以找到键值 18,然后再拿到页 3 中的指针 p1,定位到页 8。

③同样的页 8 页不在内存中,我们需要再去磁盘中将页 8 读取到内存中。

将页 8 读取到内存中后。因为页中的数据是链表进行连接的,而且键值是按照顺序存放的,此时可以根据二分查找法定位到键值 18。

此时因为已经到数据页了,此时我们已经找到一条满足条件的数据了,就是键值 18 对应的数据。

因为是范围查找,而且此时所有的数据又都存在叶子节点,并且是有序排列的,那么我们就可以对页 8 中的键值依次进行遍历查找并匹配满足条件的数据。

我们可以一直找到键值为 22 的数据,然后页 8 中就没有数据了,此时我们需要拿着页 8 中的 p 指针去读取页 9 中的数据。

④因为页 9 不在内存中,就又会加载页 9 到内存中,并通过和页 8 中一样的方式进行数据的查找,直到将页 12 加载到内存中,发现 41 大于 40,此时不满足条件。那么查找到此终止。

最终我们找到满足条件的所有数据,总共 12 条记录:

(18,kl), (19,kl), (22,hj), (24,io), (25,vg) , (29,jk), (31,jk) , (33,rt) , (34,ty) , (35,yu) , (37,rt) , (39,rt) 。

下面看下具体的查找流程图

详解mysql中聚集索引和非聚集索引

利用非聚集索引查找数据

 

详解mysql中聚集索引和非聚集索引

读者看到这张图的时候可能会蒙,这是啥东西啊?怎么都是数字。如果有这种感觉,请仔细看下图中红字的解释。

什么?还看不懂?那我再来解释下吧。首先,这个非聚集索引表示的是用户幸运数字的索引(为什么是幸运数字?一时兴起想起来的:-)),此时表结构是这样的。

详解mysql中聚集索引和非聚集索引

在叶子节点中,不再存储所有的数据了,存储的是键值和主键。对于叶子节点中的 x-y,比如 1-1。左边的 1 表示的是索引的键值,右边的 1 表示的是主键值。

如果我们要找到幸运数字为 33 的用户信息,对应的 sql 语句为:

MySQL

1

select * from user where luckNum=33

查找的流程跟聚集索引一样,这里就不详细介绍了。我们最终会找到主键值 47,找到主键后我们需要再到聚集索引中查找具体对应的数据信息,此时又回到了聚集索引的查找流程。

下面看下具体的查找流程图:

最后附上常见的关于mysql中聚集索引和非聚集索引的总结

1、mysql的innodb表,就是索引组织表,表中的所有数据行都放在索引上,这就约定了数据是严格按照顺序存放的,所以不管插入的先后顺序,它在那个物理上的那个位置与插入的先后顺序无关。

2、聚集索引,叶子节点存的是整行数据,直接通过这个聚集索引的键值找到某行

3、聚集索引,数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。

4、聚集索引,数据行和相邻的键值紧凑地存储在一起,因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚集索引

5、非聚集索引,叶子节点存的是字段的值,通过这个非聚集索引的键值找到对应的聚集索引字段的值,再通过聚集索引键值找到表的某行,类似oracle通过键值找到rowid,再通过rowid找到行

6、mysql的innodb表,其聚集索引相当于整张表,而整张表也是聚集索引。默认通过主键聚集数据,如果没有定义主键,则选择第一个非空的唯一索引,如果没有非空唯一索引,则选择rowid来作为聚集索引

7、mysql的innodb表,因为整张表也是聚集索引,select出来的结果是顺序排序的,比如主键字段的数据插入顺序可以是5、3、4、2、1,查询时不带order by得出的结果也是按1、2、3、4、5排序

8、通俗理解

聚集索引:类似新华字典正文内容本身就是一种按照一定规则排列的目录

非聚集索引:这种目录纯粹是目录,正文纯粹是正文的排序方式

每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序 

长按下方二维码关注精致的程序员,成为一个技术过硬,外表精致,灵魂有趣程序员