MySql索引结构分析

266 阅读6分钟

一.索引数据结构

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

1.二叉树

1.正常数据查询情况下,比如我查询索引是89的这条数据,只要查询两次就可以查询到了,效率还是很高的

2.但如果是单边增加的数据他的效率并不是很高,比如我查询的是索引是6的这条数据,依旧需要查询6次

2.红黑树(二叉平衡树)

1.对比上面的二叉树,我们会发现红黑树其实也是一个二叉树,但是当你单边树结构的一边比另外一边高的比较多的时候,它会帮你做一次平衡的操作,所以当你查询6这条索引数据的时候只需要查询3次,要比普通二叉树效率高很多

3.Hash表

1.当存储索引的时候,它会对你的索引做一次hash运算(MD5,CRC16,CRC32),通过hash计算就可以定位出数据的存储位置,然后放到一个hash桶里面(相当于一个数组结构,数据存放在某个数组索引所在位置的链表格子(用来存放索引字段和数据所在的磁盘地址)里面,当发生hash碰撞的时候,会在所在数组索引的链表格子里面增加一个节点用来存放新的数据),所以当我们根据某个索引字段进行某个表查询的时候,会先把索引字段通过hash计算定位出数据的存储位置,然后根据索引字段遍历那个链表上的数据进行比对

4.B-tree

1.B-tree每一个节点都是从左到右从小到大的

2.根据二叉树和红黑树,我们可以思考它的树的高度越高,我们磁盘io的次数就越多,那我们就想办法把树的高度降低,这样我们磁盘io的次数也就降低了

3.为了解决树高度的问题,B-tree把根节点做了横向的扩展,根节点不会只存储一个索引数据,它会专门划分一个磁盘索引页用来存储根节点的索引数据,这样就解决了树高度的问题

5.B+tree

1.B+tree每一个节点都是从左到右从小到大的

2.B+tree叶子节点有双向指针

3.如果出现需要平衡的情况下会把每个节点的最左边的索引提到上个节点去

4.根据二叉树和红黑树,我们可以思考它的树的高度越高,我们磁盘io的次数就越多,那我们就想办法把树的高度降低,这样我们磁盘io的次数也就降低了

5.根据B-tree,我们也可以思考B-tree虽然大致解决了树的高度问题,但是他的每个非叶子节点都会存储数据,非叶子节点上的横向扩展性虽然提高了不少,但还是存不了太多的索引

6.mysql的一次磁盘io查找数据耗费的时间要比我们在内存中定位某个索引的位置时间要长很多,所以B+tree把叶子节点用来存储数据,非叶子节点用来存储索引和下一个索引页的地址,让其尽量横向扩展用来存放更多的索引(冗余)和下一个索引页地址,以降低树的高度和磁盘io的次数以及存放更多的数据

7.mysql默认B+tree的非叶节点的大小是16kb,可以改但是不推荐,这个值是mysql做了多次优化后得到的值,比如我们索引用bigint,那它的大小大概是8个字节,下一个文件的磁盘地址大概占到6个字节,那我一个非叶子节点大概可以放1170个索引

8.叶子节点用来存放我们的数据的,假设叶子节点的大小也是16kb,我们每条数据假如它是几十个字段的表结构,那它那条数据的大小撑死了也就1kb,那我们一个叶子节点的页码存放的是16条数据,这个我们可以算一下这个索引结构可以存放1170x1170x16,大概可以存放2190w条左右的数据,仅仅需要三次磁盘的io(真真我们的mysql可能把根节点放到内存的,这样的话只需要两次的磁盘io,可能更高的版本mysql会把所有的非叶子节点都放到内存里,这样仅仅需要一次的磁盘io)

二.MySql的索引结构选择

1.二叉树:如果我们的数据索引是单边增加的形式,其实我们的查询效率并不高,所以mysql不选择二叉树作为他的索引数据结构

2.红黑树:红黑树解决了二叉树单边增加的问题,但是我们可以想象一下如果我们数据库的某个数据表有500w条数据,那其实就会有500w条索引,每个单边会有250w条数据索引,那这个时候他的树的高度是非常高的,刚好我这次数据在某个单边的叶子节点,因此在数据量大的情况下红黑树也是不太理想的,所以mysql也不选择红黑树作为他的索引结构

3.hash:理想情况下,我根据某个索引字段进行hash运算就可以直接定位到数据所在磁盘的位置,但是在我们实际开发中,99.99%的情况下我们选择的是B+tree,而不是hash,主要原因hash仅能满足"=","in",不支持范围查询,还有个原因就是因为hash冲突

4.B-tree:B-tree大致解决了二叉树和红黑树的高度问题,但是它的非叶子节点不仅仅存放了索引还存放了索引所在的数据,这样的话他的一个索引页还是存放不了太多的索引而且它的索引页不支持双向指针也就无法支持区间查询(范围查询),所以mysql不会选择b-tree

5.B+tree:对比B-tree,B+tree它非叶子节点只会用来存放索引数据和下一个索引页的地址,所以他的横向扩展更加的完善,也就是非叶子节点可以存放更多的索引数据,那他的树高度也会更低,最后分析我们发现B+tree的高度由我们非叶子节点能放多少个索引来决定的,我一个非叶子节点能放更多的索引,那我存储同样的数据记录,树的高度就越低,那磁盘io的次数就越低,而且它的叶子节点是双向指针,这样也就是说它支持区间查询(范围查询),所以mysql选择B+tree作为他的索引结构