mysql索引数据结构的分析--B树和B+树的数据结构

本文是对该博客的理解:http://www.cnblogs.com/vianzhang/p/7922426.html

1)二叉查找树
在这里插入图片描述
特点是L<= Center <= R.
故深度为n的节点的查找次数为n。
二叉查找树可以任意地构造,同样是2,3,5,6,7,8这六个数字,也可以按照下图的方式来构造:
在这里插入图片描述
这课二叉查找树的效率就比较低了。因此,如果希望查询效率高,整体树的深度就必须小,也就是二叉树的左右子树尽可能平衡。

2)平衡二叉树(AVL tree)
特点是在二叉查找树的基础上(L<=C<=R),增加了要求任意两个子树的高度差不超出1
在这里插入图片描述
这样做之后,任意一个节点的查找不会超出O(log2n)(n为所有节点的数目)

  1. B-Tree: 平衡多路查找树
    B树中的B是指平衡的意思。它是转为磁盘等外设存储设备设计的一种平衡查找树。
    先介绍一下磁盘的相关知识。
    系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,一个block一般是8个扇区,每个扇区512 byte,故一个block是4k byte。从磁盘读数据的时候是会把同一个block下的数据一次性全部读取出来的(顺序读写),而不会仅仅读取制定的某一个。

对于InnoDB引擎来说,数据存储和查询的基本单位是Page(页),页也是innoDB引擎存储的最小单元(默认是16KB,可以设置为4K或8K)。当页大于block时,mysql申请磁盘空间时就会申请连续的磁盘块block以达到一页的大小(例如16k,或者8k)。Innodb读取磁盘数据到内存中也是以页为单位的。
由于磁盘IO的速度比内存操作慢1000倍,那么一般衡量数据库的索引查询效率就是看一次查询需要的磁盘IO的次数了。
一般的二叉树可以做到log2n,但是这对数据库还是不够的。考虑到磁盘一次顺序读取一个block这个特点。我们可以将二叉树做成多路。
(我感觉可能一个指针指向的不是一个磁盘块,而是一页,一页里面是连续的1~4个block)
在这里插入图片描述
上图是一个B树(3阶,3代表每个节点最多有3个孩子)
为了描述B树,我们需要定义一个二元组[key, data],其中key是关键字,对应表中的主键值,data则是一行记录中除了主键外的数据,key唯一
一个m阶B树有如下特点:
1)每个节点最多有m和孩子;
2)非根节点和非叶子节点,至少要有m/2个孩子;
3)根节点如果不是叶子节点,就至少要有2个孩子;
4)所有叶子节点都在同一层,叶子节点不包含关键字信息
5)非叶子节点会包含若干关键字和指针,且指针个数比关键字多1个。每一个指针都指向它的一个子节点,子节点中存储的数据的范围是该指针关键字(只有一个关键字就是以它为极值)。例如磁盘块2中p1指向磁盘块5,磁盘块5张的数据最大不超出8;而p2指向磁盘块6,其中的数据必须是(8,12)(主键没有相等的情况)
6)每个节点对应一个磁盘块,也就是说一个节点的最大存储空间是16kb
7)key值分散在整个B树中,并且每个节点不仅仅有关键字(主键),还有具体数据(一行记录)

拟查找关键字29的过程:
根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
比较关键字29在区间(17,35),找到磁盘块1的指针P2。
根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
比较关键字29在区间(26,30),找到磁盘块3的指针P2。
根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

4)B+ Tree: B+树
B+ Tree是对B树的进一步优化,使其更适合外存储索引结构,也是InnoDB引擎的索引底层的数据结构。
对于B树来说,由于每个节点不仅存储key值,还有data值,那么一个节点(最大16k)能存储的数据量就有限了,在数据库数据量比较大的情况下树的深度就比较大了,这会导致每次查询磁盘IO次数增加,降低查询效率。
基于这点,又额外做了优化,在B树基础下,B+树的非叶子节点只存储键值(主键值),在叶子节点下,不仅仅有主键值,还有data(记录中除主键外的信息)。(这也要求了每一个节点的键值一定要由它的子节点来继承,这样所有的主键值都会最终落到叶子节点下
在这里插入图片描述
此外,每个叶子节点还是链式结构,一个叶子节点会指向下一个节点。此外,整个B+ Tree上还有2个指针,一个指向根节点,一个指向关键字最小的叶子节点。这样会便于对B+树做两种查找运算:1)对于主键的范围查找和分页查找;2)从根节点开始的随机查找

上述结构的最大优点是每个非叶子节点都可以存储非常多的主键值,这可以大幅降低整个B+树的高度。

InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为〖10〗3)。也就是说一个深度为3的B+Tree索引可以维护103 * 10^3 * 10^3 = 10亿条记录。
实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在24层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要13次磁盘I/O操作。

数据库中的B+Tree索引可以分为聚集索引(clustered index)和辅助索引(secondary index)。上面的B+Tree示例图在数据库中的实现即为聚集索引,聚集索引的B+Tree中的叶子节点存放的是整张表的行记录数据。辅助索引与聚集索引的区别在于辅助索引的叶子节点并不包含行记录的全部数据,而是存储相应行数据的聚集索引键,即主键。当通过辅助索引来查询数据时,InnoDB存储引擎会遍历辅助索引找到主键,然后再通过主键在聚集索引中找到完整的行记录数据。

猜你喜欢

转载自blog.csdn.net/xiaohesdu/article/details/85252190