MySql索引的数据存储结构

61 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

索引存储的必要条件

作为索引它的主要目的就是定位数据的位置,快速响应所要查找的数据,同时要支持索引范围查找以及数据排序。在这些硬性条件的基础上进行数据存储,那么数据结构的选择必是个难题。

数据结构的选择

根据多种数据结构来进行选择,hash结构跟树结构应该会是首选,但是又取决于各种原因hash结构相对没那么好,具体原因如下:

  • hash结构根据哈希算法计算初哈希值就能够快速定位索引数据,但是存在哈希冲突的可能,查询性能还会受哈希冲突的影响。不支持范围查找且查询时无法排序,hash结构索引数据是无序的,在范围查找的情况下就相当于全表查询,这种情况性能也会大大下降。简而言之hash结构数据查询性能很不稳定,所以并不是个好的选择。
  • 树结构相比hash结构优势也比较明显,首先树结构的数据存储是有序的,对于范围查找以及数据排序的支持都相对友好。对于按索引查找的数据,根据树结构的二分查找法也能够很快定位到数据的位置,只要树能够平衡高度不会太高,查询性能基本相对稳定。

本文也就根据树结构的存储结构做进一步分析。

BTree与B+Tree

上面提到主要以树结构作为存储,那么相对合适的树结构就是BTreeB+Tree两种,由于这两种树结构都是多路平衡二叉树高度较矮,所以两者都是常用于数据库存储引擎实现索引存储。对于这两种树结构具体分析对比请接着往下看:

  • BTree:用这种数据结构来存储大量数据的时候,它的整棵树高度相对二叉树会矮很多。对于数据库来说,数据都是存储在磁盘中的,所以树的高度就决定了磁盘IO次数,树的高度越矮相对的磁盘IO次数就越少,数据读取的性能就会大大提升,所以这就是数据库会采用BTree做索引数据存储结构的原因。BTree数据存储结构如图:

image.png

如图:一组数据在BTree结构进行存储,假设一个树节点的大小能够存放两个索引值、两个数据行、三个范围指针指向子节点,便于索引遍历的时候查找节点数据,可以看出无论是根节点、还是叶子节点存放的都是一样的数据内容。

  • P1:指向小于节点索引数据的子节点。
  • P2:指向大于节点索引最小值且小于节点索引最大值范围的字节的。
  • P3:指向大于节点索引数据的子节点。
  • B+Tree:在MySQLInnerDB存储引擎中使用的是BTree的增强版B+Tree数据结构,也就是使用B+Tree来做索引和数据的存储结构。B+Tree数据存储结构如下:

image.png

MySQLInnerDB存储引擎之所以使用B+Tree而不用BTree的原因主要有以下几点:

  • B+Tree的非叶子节点仅存储索引,与BTree相比一个非叶子节点就可以存储更多的索引值,而数据全部存储在叶子节点上,只要找到了索引位置就能快速定位到数据行,所以一定程度上是能够减少磁盘IO次数,特别在数据量越大的时候表现更为明显。
  • B+Tree的叶子节点的数据使用双向链表进行关联,便于范围查找。
  • 在全表扫描方面B+Tree所有数据都存储在叶子节点,所以只需要扫描叶子节点即可。

聚簇索引与非聚簇索引

  • 聚簇索引 聚簇索引指的是将数据与索引存储到一起,B+Tree即是将数据与索引存储到叶子节点。聚簇索引默认都是以主键来作为索引值,如果表没有定义主键那么MySql会默认使用隐藏主键代替。

  • 非聚簇索引 非聚簇索引指的是数据与索引分开存储,B+Tree结构中即是叶子节点仅存放了索引列的数据,再根据索引列进行一次回表获取数据。

  • InnerDB主要采用的就是聚簇索引,其在磁盘上产生的文件有两个。其中.frm存储表结构信息,.ibd存储的就是索引与数据。该数据存储方式对于增删改查都有需求的关系型数据库支持比较友好,性能也相对较稳定。

  • MyIsam采用的是非聚簇索引,其在磁盘上产生的文件有三个。其中.frm存储表结构信息,.MYI存储的是索引信息,.MYD存储数据,如此就可以看出非聚簇索引的索引值与数据是分开存储的。MyIsam存储引擎相对于只做查询的业务会支持比较友好,由于数据与索引分开存储,在更新数据的时候性能开销较大,所以一般采用该存储引擎的数据库都做只读。

总结

数据库是作为数据存储的必要工具,我们不单要会用会写SQL,更多的还是要多理解一下底层的一些实现,这样有助于我们在开发时如何进行数据库选型,分析业务场景选择数据库存储引擎,并合理的设计表索引,让数据库能够在我们的业务中将性能发挥的更好。