之前看過許多關於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。頁分裂。
瞭解應用場景後再去看具體實現更容易懂並且印象深入
。