图灵学院Java架构师-VIP-MySql索引底层数据结构

MySql索引底层数据结构

索引的本质

索引是帮助MySQL高效获取数据的排好序的数据结构

很多文章都讲过,Mysql底层的数据结构是通过B+Tree实现的,那具体为什么要用这种结构来实现呢?我们从各种数据结构分析一下。假如数据库中的数据是这个样子的。

1. 不用索引的方式查找

因为数据是存在磁盘上的,所以如果想要查找表中col2 = 89的这条记录,则需要进行6次的磁盘IO进行查找,效率很低

2.二叉树

比如给col2列中使用二叉树的方式加入索引,结构会变成这个样子,此时我们想查找col2 = 22的这条记录,利用二叉树特性,右节点>父节点>左节点。我们只需要进行3次IO查找即可找到数据

二叉树

看起来这种方式也不错,但是如果我们是在col1中也使用这种方式存储会是什么情况呢?下图所示,比如此时想查找col1 = 6的数据,还是要进行6次的磁盘IO,这样的方式存储就没有什么用途了吧

二叉树

3.红黑树

红黑树是二叉树的一种,但它可以自动对一棵树进行平衡,例如上图中col1的情况,它将会用这种结构存储,如图。这种方式看来,应该没问题了吧?但是想一想,表中数据如果有上百万条记录,那这个树的高度会有多高?树的高度也就决定了磁盘IO的次数。为解决这个问题,是不是可以考虑减少树的高度呢?下面介绍下B-Tree

红黑树

4.B Tree

图中所示,B树事实上是一种平衡的多叉查找树,也就是说最多可以开m个叉(m>=2)我们称之为m阶b树。

通过B Tree存储结构如下所示(假设是个4阶B树)。BTree是二叉树的一种,所以也具有二叉树的特点(右节点>父节点>左节点),此时,比如我们想要查找20这个位置,则只需要进行3次磁盘IO,即可定位到记录。在mysql中,一排最多能存储多少个呢?假设字段是BitInt类型(8字节),数据与数据之间存在指针空间(6字节),假设表中数据一行大小为1kb。Mysql默认存储空间是16KB,由此可以得知,如果用bigint类型存储,一排最多可以存储 16*1024/(8+6+1024) ≈ 15个索引。假设一个高度为3的树,最多可以存储多少个索引呢? 15 * 15 * 15 = 3375。那有什么办法能再次优化呢?我们来看下B+Tree的存储结构


5.B+Tree

B+Tree是B Tree的变种,形式上和BTree差不多,只是把数据做了一次冗余,所有的数据存在子节点上,如图所示。通过这种冗余的方式,让每一层中存储的索引更多,假设表中的一行记录需要1KB空间存储,一个高度为3的B+Tree最多可以支持多少索引数据?1170 * 1170 * 16 = 21,902,400,由此可见,一个高度为3的B+Tree如果存满的话,最多可以放2千万条索引数据(因为数据需要冗余,数值要小于计算出来的值,具体没算),查询时最多进行3次磁盘IO即可定位到记录。

最下边那个链表样子的指针是做什么用的?范围查询(下图中应该是个双向指针)。比如说我们想查找>15的索引对应的数据。如果按照BTree方式查找,需要不断的返回父节点再次进行查询。而B+Tree通过这个链表指针,直接获取到下一个节点。

6.Hash表

Mysql支持使用Hash方式建立索引,如图。我们都知道Hash算法是一种散列算法,查找的时间复杂度为O(1),那这么好的办法,Mysql为什么默认不使用Hash存储索引呢?答案是范围查询,如果是范围查找,Hash表的方式就搞不定了,只能走全表查询。所以如果表中的字段不需要用到范围或条件查询。那么用Hash结构存储则会快很多。


MyISAM 索引实现 

MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录的地址。下图是 MyISAM 索引的原理图,MyISAM是非聚集索引,索引和数据在磁盘中是分开存储的,索引存储的是磁盘位置。


InnoDB 索引实现 

在InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶点data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。


InnoDB 与 MyISAM存储数据方式是不同的,MyISAM存的是磁盘地址,而InnoDB主键索引存储的是数据,非主键索引存储的是主键数值,这就是为什么 InnoDB 要求表中必须要有主键,如果没有显式指定,则 MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,类型为长整形。

为什么推荐使用整型的自增主键?

因为使用B+Tree结构存储,如果主键生成的没有规律,在新增时,会引发B+Tree分裂,影响效率,如果是自增类型,仅改变末尾处的指针数据即可。所以我们要避免使用uuid等这些字段作为表中的主键字段。

你可能感兴趣的:(图灵学院Java架构师-VIP-MySql索引底层数据结构)