文章目录
转载: https://www.cnblogs.com/shengguorui/p/10695646.html
一 B+Tree 和 B-Tree
在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。
B-Tree
B+Tree , + 姑且理解为plus加强版吧!
二 InnoDB中一个3层B+树最多大概可以存放多少行数数据?
首先,在innodb存储引擎里面,最小的存储单元是页(page),一个页的大小是16KB。如果我们在数据库的命令行输入如下命令,那么可以返回:
这就说明了一个页的大小为16384B,也就是16kb。
数据表中的数据都是存储在页中的,所以一个页中能存储多少行数据呢?
假设一行数据的大小是1k,那么一个页可以存放16行这样的数据。那如果想查找某个页里面的一个数据的话,得首先找到他所在的页,但是如果按照普通方法,也就是遍历的话,就得一个页一个页的查找,显然太慢了。
innodb存储引擎我们都知道使用B+树的结构来组织数据。如果是在主键上建立的索引就是聚簇索引
,即只有在叶子节点才存储行数据
,而非叶子节点里面的内容其实是键值和指向数据页的指针。
举个例子,如果是两层的B+树的话,结构如下(盗图):
注:”仔细看图里面,每个节点都标注了他所属的page。
这里B+树的每一个节点都是一个页,比如根节点就是page:3(在InnoDB的表空间文件中,约定page number为3的代表主键索引的根页
),存储的就是页指针(Pn)和主键值(页指针首id值)。
比如执行select * from user where id=5;整个过程是:
首先找到根页,这里是page:3,然后利用二分法中间id=7,大于5向左,4<5,所以找到了page:5的指针,进入page:5。然后再利用二分查找在这一页里面查找id=5的数据。
问题1: 因此,我们首先解决一个简单一点的问题:那么如果是2层的B+树,最多可以存储多少行数据?
如果是2层的B+树,即存在一个根节点和若干个叶子节点,那么这棵B+树的存放总记录数为:根节点指针数*单个叶子节点记录行数。
因为单个页的大小为16kb,而一行数据的大小为1kb,也就是说一页可以存放16行数据。然后因为非叶子节点的结构是:“页指针+键值”,我们假设主键ID为bigint类型,长度为8字节(byte),而指针大小在InnoDB源码中设置为6字节(byte),这样一共14字节(byte),因为一个页可以存放16k个byte,所以一个页可以存放的指针个数为16384/14=1170
个。
因此一个两层的B+树可以存放的数据行的个数为:1170*16=18720(行)。
问题2 最后再回到原来的问题:一个三层的B+树可以存放多少行数据呢?
首先,结合上面的图,我自己画了一个三层的B+树的示意图:
最右边的是page:7,画不下去了省略。
也就是说第一层的页,即根页(page:3)可以存放1170个指针,然后第二层的每个页(page:4,5,6,7)也可以存放1170个指针。这样一共可以存放1170*1170个指针,所以一共可以存放1170*1170*16=21902400行记录
。也就是说一个三层的B+树
就可以存放千万级别的数据了。而每经过一个节点都需要IO一次,把这个页数据从磁盘读取到缓存,也就是说读取一个数据只需要三次IO
。
问题3:为什么MySQL的索引要使用B+树而不是其它树形结构?比如B树?
回答:因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据
,只能增加树的高度,导致IO操作变多,查询性能
变低;
三 二分查找时间复杂度
数据量为n
一次查询 n//2
二次查询 n/2/2 --> n/2^2
m次查询 n/2^m
如果到最后只有一个数据了 n/2^m = 1
–> 2^m = n
m = logn
时间复杂度就是 O(logn)