之前看过许多关于B+ Tree
的文章,当时看了总以为明白了,但是没过多久就又要忘了。直到我看了掘金小册:Mysql是怎么运行 第7,第8章
才终于明白了B+ Tree究竟是怎么回事。若是对Mysql内部具体如何实现感兴趣的能够去看小册,我本身看这2章,每章都花了2个小时,毕竟介绍的概念有点多。 我这篇文章至关于对这2章内容的概况总结吧,也能够当导读看,看完这个,再去看小册子可能就没那么吃力了。(ps, 这本小册子是我见过最详细介绍Mysql内部原理的系列文章。)算法
1.数据是怎么存储在InnoDB中的
2.若是快速找到一条记录?
3.搜索查找记录的流程是怎么样的?
4.页分裂是什么?sql
没错,首先忘了什么数据结构。
在介绍Buffer Pool
时提到过数据库
InnoDB 是以 页(通常为大小为16K) 为单位,从磁盘文件中读取数据 到内存的。 一页 包含多条记录(每页至少要有2条记录)数据结构
CREATE TABLE `school` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
delimiter;;
CREATE PROCEDURE idata ( ) BEGIN
DECLARE
i INT;
SET i = 1;
WHILE
( i <= 25 ) DO
INSERT INTO school
VALUES
( i, 'school' );
SET i = i + 1;
END WHILE;
END;;
delimiter;
CALL idata ( );
复制代码
如今咱们建立了一张school 表格,而且插入了25条记录。
现实场景中,一页能够记录几百上千条记录。这里为了方便理解,咱们假设
一页只能存放5条记录。那么存放状况就如图:spa
双向链表
,这样方便范围查找。不必定连续
链表
知道了记录的存储状况,那么要查找某个id的记录,就变成了2个问题:设计
快速定位
某个Key(这里为id) 存在在哪一个页面中?为了快速定位,最容易想到的就是创建字典了,好比(1,200),(2,200),(6,210) 这样的确可以知足快速查找的需求,可是比较浪费空间。
因此转换一下方法:code
最小值
,value 记录对应数据页
的页号
。这样造成了目录项。
例如,如今咱们有25条记录,每5条记录存放在1页中,那么至少
有5页,因此至少
有5个目录项
。目录项
管理也经过页的形式进行。5条记录为1页,那么5个目录项就造成了1个目录页
。目录页中的记录
(即目录项)也是按照顺序排列这就是最简单的一个B+Tree 了。叶子节点为数据页,存放数据。(为何说对于聚簇索引,索引即数据?)而非叶子节点存放的是目录项。cdn
select * from student where id = 14
复制代码
咱们要从查id = 14 的数据。那么从根节点``(这里是页400)
开始查找,页400有5个记录,经过二分查找
算法进行查找,由于11 < 14 < 16 因此 14记录对应的页和11记录对应的页同样。(请牢记下面2个特性: 目录项中的key 记录的是对应页中key的最小值
。而且无论数据页
仍是目录页
其中的记录都是有序
的。)
那么14 对应的页就是212号页。而后再到页212号中进行二分查找找到
对应数据。blog
若是这个时候再插入一条数据。排序
insert into student values (28,'王五')
复制代码
因为数据页都满了,因此必须新开一个页面来存放28这条记录。假如这个页面为310页。但同时因为目录页400页也满了,无法记录(28,310)这个目录项,因此又必须加个新的目录页
例如410页来存放新的目录项。这个时候因为有2个目录页了,因此须要新建新的目录页
来管理目录页,``没错,目录页中的记录不必定是指向数据页的,也可能指向目录页。
看起来会变成下面这样:(图有点丑,有好的画图软件麻烦推荐下)
构建过程跟我上面所提的过程是不一样的。
上面的过程是为了让你们首先了解下随着数据插入,页面(
不论是数据页仍是目录页
)是会增长的。我作出这个流程是为了让你们知道有这么一个流程,可是具体实施,InnoDB的大神考虑的固然比咱们要多,能够说是
异曲同工
吧,方法不一样,但要达到的目的是同样的:就是现有页面存放不了新插入的数据时会进行页分裂。具体流程感情的小伙伴能够查看小册子。我介绍最重要的点:
根节点肯定后是不会变的
。(上面说的根节点从400 变成页420在真实数据库中是不会存在的。)真实的流程相似于:假设一开始只有5条数据都存放在页10当中,那么这个时候页10便是数据页又是根节点。
这个时候又新插入一条数据,Innodb会把页10
复制获得数据页20
,而后对数据页20
进行分裂,把数据页20
中的部分数据迁移,获得数据页30
,而后新插入的数据根据索引的大小插入到对应的页20或页30
中。这个时候原来的页10变成了目录页,
记录的目录项对应页20,和页30。可是页10仍是根节点
。数据页
中找到对应的记录,设计了目录页
。目录页和数据页 构成了一棵B+ Tree。页分裂。
了解应用场景后再去看具体实现更容易懂并且印象深入
。