淺析存儲引擎(3)-B-tree

 

淺析日誌結構的存儲引擎(1)-bitcask
淺析日誌結構的存儲引擎(2)-SSTable和LSM-Tree

前面兩篇文章介紹了比較好理解的日誌結構引擎LSM-Tree,但它們不是最常見的索引類型。目前最廣泛使用的索引結構是B-tree。B-tree維護着按key排序的key-value對,這樣可以實現高效的key-value查找和區間查詢。

一、B-tree的存儲

前面的文章提到,日誌結構存儲引擎將數據庫分解爲可變大小的段,並且始終按順序寫入段(追加寫)。而B-tree將數據庫分解成固定大小的塊和頁,通常是PAGESIZE大小4KB(也可能更大),頁是讀/寫的最小單元,這種設計也符合磁盤的讀取規則。

以mysql爲例,我們都知道InnoDB的存儲數據格式是按主鍵排序的(MyISAM和InnoDB的區別),數據都存儲在最底層葉子節點。某一頁被指定爲B-Tree的根,如下圖:

假設我們需要查找key=251,需要沿着200-300的區間,最後找到一個包含單個key=251的父頁,再從這個父頁中找到存儲了key=251的數據頁(或者塊)的偏移量,從磁盤中讀取數據。

假設每層樹維護500個葉子節點,那麼四級樹就可以存儲500的4次方*4KB=256TB的數據,查詢非常高效。

二、如何解決數據更新的問題?

LSM-Tree的數據更新是追加更新文件(最終刪除過時的數據)。

和LSM-Tree不一樣,B-Tree-底層的基本寫操作是使用新數據覆蓋磁盤上的舊頁。可以理解爲磁頭先移動到正確位置,然後旋轉盤面,最後用新的數據覆蓋相應的扇區(SSD的覆蓋寫更加複雜,需要擦寫更大的數據塊,可能會產生寫放大)。也就是說當數據被覆蓋時,索引上對該頁的引用並不需要改變。

當然也有例外情況

情況1:假設新覆蓋的數據大小超過了原來的頁大小,就需要分裂頁,同時覆蓋其父頁,以更新對兩個子頁的引用(頁的偏移量)。

情況2:假設只增加新key,當找到包含其範圍的頁時,假設頁沒有足夠的空間來容納新key,那麼就需要分裂爲兩個半滿的頁,並且父頁也需要更新對子頁的引用。如下圖,插入新key"334":

風險:上述的情況1和情況2在需要更新子頁的同時,還需要更新父頁對子頁的引用,由於至少需要兩次磁盤操作,很有可能更新完子頁數據庫就崩潰了,來不及更新父頁,產生了孤兒頁。常見B-tree的實現在磁盤上增加重做日誌,這是一個僅支持追加修改的文件,作用類似前面講到的SSTable的日誌文件,用於崩潰時恢復數據。

 

參考《數據密集型應用系統設計》

原文出自:https://blog.csdn.net/daiyudong2020/article/details/104717904

end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章