mysql innodb 索引结构_mysql innodb索引结构及相关原理-Go语言中文社区

本文深入探讨了B+树的数据结构及其在MySQL InnoDB引擎中的应用。介绍了页的概念、页目录的作用以及B+树如何优化数据检索过程。此外,还详细解释了InnoDB如何利用B+树实现高效的索引机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在优化线上代码,优化过程中,对数据库进行了一系列的学习和基础巩固,看了很多大佬写的文章,整理了一下,记录在这里~

参考文档:

B+tree的结构

在操作系统中,当我们往磁盘中取数据的时候,如果我们想要取出1kb的数据时,会发现,操作系统取出了4kb的数据,这是因为操作系统中页的大小是4kb。这是为什么呢?

当一个程序访问了一条数据之后,很有可能在此访问这条数据或访问这条数据相邻的数据。因此,干脆直接把4kb的数据全部取出,放到内存中,下次再来访问时,直接从内存中取出,减少了磁盘IO。

假设,我们现在有一张用户表,我们要找出id=5的数据,在没了解页这个概念之前,最原始的方法就是遍历。我们会不断的从磁盘中取出一条数据,然后判断这条数据是不是id=5,如果不等于,会继续向后遍历,此时,我们会查找5次,也就是经过了5次磁盘IO。

现在,我们将页引入,当我们取出id=1的数据时,操作系统会将id=1所在页的全部数据(id=1到id=4)取出,放到内存中,我们继续向后遍历,接下来的遍历,会从内存中取出;当取出id=5的数据时,操作系统会再次将该id所在页全部取出。此时我们会发现,只经过了2次磁盘IO

在MySQL的InnoDb引擎中,页的大小是16KB,是操作系统的4倍,而int类型的数据是4个字节,其它类型的数据的字节数通常也在4000字节以内,所以一页是可以存放很多很多条数据的,而MySQL的数据正是以页为基本单位组合而成的。

页的结构如下:

26ad32a9bfeb2a30416afc81db1f48dd.png

页目录

通过对上面页的了解,我们在查找数据的时候,已经可以做到减少磁盘IO了。但是我们可以发现其实页中的数据结构就是一个链表。链表的优点是插入和删除很快,但是查询需要按指针方向去遍历。假设现在一页中有上百万条数据,最坏的情况他可能会遍历上百万次,即使在内存中,效率也不高。

页目录就像书目录一样,会告诉我们哪个标题从哪一页开始。页目录的结构如下:

6abbe165f578ab2462e5bdae400aee44.png

假设我们查找id=3的数据,首先会找到目录2,然后对目录2中的数据进行查找。当然我们能通过目录快速的找到数据,其实主要基于这些数据已经经过了排序。因此,可以得知,在我们插入数据时,数据库会对数据进行排序。

当然,不可能只有一页数据,多页数据的结构如下:

b9e6128459e02c55d71d89ef06b44e84.png

但是需要注意的是,在开辟新页的时候,数据并不一定在新开辟的页上,而是需要进行和所有页的数据的比较,从而来决定数据存放的位置。

目录页

从上图我们可以发现,多页之间也是通过指针相连,他们其实就是链表。如果页的数量过多,又会造成遍历过多,此时,我可以想到,有没有一个结构,可以像页目录那样,可以优化页内数据呢?

页内数据和多页他们本质上都是链表,所以我们可以采用相同的方式优化,这种方式叫目录页。

4ba96ada2111b3a78566de93b0e065dd.png

需要注意的是,目录页的本质也是页,但是,普通页中村的数据是项目数据,而目录页中村的数据是普通页的地址。

B+tree

5e6e5e457ee4b6613eadf02963ca34e2.png

从上面的图我们已经可以看出,这其实就是b+tree的结构了。一般来说,树的深度是3层;每个叶子就是数据页,非叶子结点就是目录页;叶子结点存放真实的数据,而非叶子结点存放目录,也就是索引。

它的优势有以下几点:

由于叶子结点上存放了所有的数据,并且有指针相连,每个叶子结点在逻辑上是相连的,所以对范围查找比较友好;

B+tree所有的数据都在叶子结点上,所以查询效率稳定,一般都是查询三次;

有利于数据库的扫描;

有利于磁盘的IO,因为他的层高不会因为数据扩大而增高(三层树高大概可以存放2000万的数据量);

InnoDB索引

我们都知道innodb索引的结构是B+tree,那么,他是怎样存放数据的呢?

b0269c63e3774398b91877d4f9785d2f.png

通过上面的图,我们可以得到以下信息:innodb的数据文件本身就是按B+tree组织的索引结构,叶子结点存放了表的完整数据,key是数据表的主键,因此,innodb数据表文件本身就是主索引。

像这种叶子结点包含完整数据的结构,我们叫它聚簇索引。聚簇索引是按照每张表的主键构造的一颗B+树,树的叶子结点存放着表中行数据。由于每张表的主键只有一个,因此数据库中每张表只有一个聚簇索引。

因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

除了主索引,还有辅助索引。每张表的辅助索引可以有多个,它的叶子结点不同于主索引,辅助索引存储着相应记录主键的值。也就是说,innodb的所有辅助索引都引用主键作为data。

c0b891d59820943e11c8c95f8bb82f9f.png

辅助索引也可以叫做非聚簇索引。非聚簇索引就是将数据和索引分开,查找时需要先查找到索引,然后通过索引回表找到相应的数据。

因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大,所以不建议使用过长的字段作为主键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值