mysql索引底层结构分析

什么是索引,索引说白了就是一种提高查询效率的数据结构,mysql底层是用B+Tree来实现的

分析B+Tree之前,我们先来看下其他的几种数据结构之间的区别以及mysql为什么底层是选择用B+Tree来实现索引的

这边网上看到一篇介绍数据结构的,可以参考

https://blog.csdn.net/qq_34436819/article/details/105731324

 

常见的几种索引数据结构

1.二叉树

2.红黑树

3.hash表

4.B-Tree

 

这边介绍一个模拟数据结构很给力的网站,大家可以去这网站上模拟一下这些数据结构是怎么存放数据的

https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

 

1.我们首先来看下二叉树:

 

mysql索引底层结构分析_第1张图片

这是一个典型的二叉树的数据结构,每个结点都只有2个字节点,我们可以看到,当数据不断的增加的时候,树的高度就会不断增加,他查找的复杂度就是树的高度,每次查询都会与磁盘做一次I/O交互,消耗比较大。

 

2.红黑树:

mysql索引底层结构分析_第2张图片 mysql索引底层结构分析_第3张图片mysql索引底层结构分析_第4张图片

红黑树不断添加数据的时候,树的结点会发生一个自旋,关于红黑树的数据结构比较复杂,这里先不做介绍,之后可能会更新新的博客做介绍,但是能看到每个结点也只有2个字节点,树的高度也会随着数据的增加不断的增加。

 

3.hash表

hash表是一种key-value的数据结构,它是将 key 通过一个哈希函数计算出一个数字,然后以该数字作为数组的下标,然后将 value 存放到对应下标的数组中。hash表可能出现的问题

    1.对于不同的 key,在经过哈希函数计算后,可能出现相同的值,就有可能出现哈希碰撞,这时候就意味着同一个数组下标处要存放两个元素了,所以这个时候将数组中的元素变为一个链表,通过链表将这两个元素串联起来

    2.hash表只适合等值查询,如果遇到范围查询等,效率就会很低,不符合实际工作场景

 

4.B-Tree

B-Tree 的特点是无论叶子结点和非叶子结点,它都存有索引值和数据;B+Tree 的特点是只有叶子结点才会存放索引值和数据,非叶子结点只会存放索引值本身。因此对于非叶子结点,一个结点中,B+Tree 存放的索引值数量会远远大于 B-Tree(因为一个结点的空间是有限的,B-Tree 要存放索引+数据,而 B+Tree 只需要存放索引),这样就导致了每个结点中,B+Tree 能向下分出更多的叉,子结点数更多。

 

那么在要存储同样大小的数据文件的场景下,用 B+Tree 存储,最终树的高度会远远小于用 B-Tree 存储的高度,所以使用 B+Tree 作为 MySQL 索引的数据结构,将来在读取数据时,发生的磁盘 IO 次数会更少,性能更优,因此最终 MySQL 索引的数据结构使用的是 B+Tree。

关于B-Tree和B+Tree可以参考以下文档

https://mp.weixin.qq.com/s/z_TNLqqJVwYKgb2kBadTwg

https://mp.weixin.qq.com/s/yLCqkrf1rvp6zJA6S-8sTQ

 

我们主要是分析mysql的InnoDB存储引擎

我们来看下InnoDB的主键索引,普通索引和联合索引的底层数据结构(图是从某个大神那边copy过来的,自己画有点麻烦)

 

主键索引

mysql索引底层结构分析_第5张图片

 

普通索引

mysql索引底层结构分析_第6张图片

 

联合索引

mysql索引底层结构分析_第7张图片

 

 

我们来看几个问题

为什么InnoDB表必须有主键,并且推荐使用整型的自增主键?

为甚InnoDB表建议要有自增的主键,尽量建主键,建整形自增的?其实很简单,设计如此,mysql设计的就是innoDB把你的数据和主键索引用B+Tree来组织的,没有主键他的数据就没有一个结构来存储。

 

建innoDB表的时候没有建主键,表也能建成功,为什么?

不建主键不代表没有主键,没有建主键innodb会帮你选一个字段,一个可以标识唯一的字段,选为默认字段,如果这个字段唯一的话,不重复,可以建唯一索引的话,就会作为类似于唯一索引,用这个字段来作为唯一索引来维护整个表的数据。如果没有,mysql会生成一个唯一的列,类似于rowid,只不过你看不到,他会用生成的这个唯一列,维护B+Tree的结构,查数据的时候还是用B+Tree的结构去查找。

 

为什么推荐整形呢?

我们想象一下查找过程,是把节点load到内存然后在内存里去比较大小,也就是在查找的过程中要不断的去进行数据的比对。假设UUID,既不自增也不是整形。问一下,是整形的1<2比较的效率高还是字符串的“abc”和“abe”比较的效率高呢?显然是前者,因为字符串的比较是转换成ASCII码一位一位的比,如果最后一位不一样,比到最后才比较出大小,就比整形比较慢多了,存储空间来说,整形更小。索引越节约资源越好。

 

为什么是自增的呢?

我们可以看一下B-Tree的叶子节点之间是没有指针的,B+Tree优化后增加了叶子节点之间的指针,如果我们遍历数据,从当前节点遍历完之后,就可以根据节点间的指针快速找到下一个节点去遍历。

 

这边插一个关于联合索引的,联合索引建立需要遵循最左匹配原则,他会先比对第一个字段,比对完第一个字段才会比对第二个字段,最后才会比对第三个字段,举个例子:

有这么一条sql,a,b,c三个字段建立了一个联合索引

select * from table where a=xxx and b=xxx and c=xxx

那么执行会跑3个索引,但是如果变成下面这条查询语句的话就只会跑前面2个索引,而不会跑c索引了

select * from table where a=xxx and b>xxx and c=xxx

 

 

个人大致理解就是这样,如果有写的不对的,欢迎一起讨论交流,谢谢!

 

你可能感兴趣的:(mysql索引底层结构分析)