爲什麼MySQL使用B+而不是使用B樹、二叉樹、AVL樹呢?(來龍去脈的去理解)

當你回答使用B+ 怎麼怎麼好的時候,其實這道面試題你就註定答不滿分了,你應該是從一步步如果演變到使用B+來做MySQL的數據結構,下面就一步一步從二叉樹——>AVL(平衡二叉樹)——>B Tree(多路平衡查找樹)——>B+ Tree的一個演變的過程來進行分析,爲什麼使用B+ Tree的?

(1)先從二叉樹開始說起:

  • 首先你得知道二叉樹是什麼吧:看下面的圖一你就該很熟悉了吧
  • 然後你得知道二叉樹查詢的時間複雜度是O(log2(n)),這樣感覺其實二叉樹的查詢效率挺高的,但是他會出現另一種現象,就是下面的圖二:
  • 這樣就導致了二叉樹的查詢效率不問題,如果運氣好的話查詢效率就很高,如果運氣不好的話,就會出現圖二的情況,因此在二叉樹的基礎上又進行的改進,演變出來了平衡二叉樹(AVL樹)

圖一:
在這裏插入圖片描述
圖二:
在這裏插入圖片描述

(2)然後到了平衡二叉樹(AVL樹):

  1. 首先你得知道平衡二叉樹的定義吧:在滿足二叉樹的基礎上,任意兩個節點的兩個子樹的高度差不能超過1:就好比下面的這個圖的一個效率很差的二叉樹,比如5節點的左子樹的高度是0,右字樹的高度是2,,所以很明顯不滿足平衡二叉樹的概念
    在這裏插入圖片描述
  2. AVL樹主要是爲了解決上面的圖出現的情況,所以現在要把上圖的二叉樹轉插入一個“9”節點然後換爲一個平衡二叉樹的情況就是下面的:
    在這裏插入圖片描述
  3. 可以看出平衡二叉樹的缺點就是:(1)維護平衡過程的成本代價很高,因爲每次刪除一個節點或者增加一個節點的話,需要一次或者多次的左旋,右旋等去維護“平衡”狀態(2)然後是查詢的效率不穩定,還是會有看運氣的成分在裏面(3)然後是如果節點很多的話,那麼這個AVL樹的高度還是會很高的,那麼查詢效率還是會很低,
  4. 還有就是節點存儲的數據內容太少。沒有很好利用操作系統和磁盤數據交換特性,也沒有利用好磁盤IO的預讀能力。因爲操作系統和磁盤之間一次數據交換是已頁爲單位的,一頁 = 4K,即每次IO操作系統會將4K數據加載進內存。但是,在二叉樹每個節點的結構只保存一個關鍵字,一個數據區,兩個子節點的引用,並不能夠填滿4K的內容。倖幸苦苦做了一次的IO操作,卻只加載了一個關鍵字,在樹的高度很高,恰好又搜索的關鍵字位於葉子節點或者支節點的時候,取一個關鍵字要做很多次的IO。因此平衡二叉樹也是不太符合MySQL的查詢結構的。

(3)然後到了使用B Tree(多路平衡查找樹)

  1. 首先你也得知道B Tree的基本概念:所有的葉子節點的高度都是一樣,這個保證了每次查詢數據的時候都是穩定的查詢效率,不會因爲運氣的影響
  2. 然後B Tree中其實每個非葉子節點內的小節點內其實都是一個二元組[key, data],key其實就是下圖的那個25這種的,然後這個data其實對應的就是數據庫中id等於25這條完整的數據記錄的內存地址(因爲在Myisam中他是數據和索引數據是分開的)

在這裏插入圖片描述
B樹的特點:

  1. 首先B Tree的每一個節點上其實是有date的,這個date其實就是
  2. 然後是B Tree查詢的效率不夠穩定,他有可能在第一個節點中就查到了數據,並且返回
  3. 他的鍵值其實都是分佈在整棵樹上的節點上的任何一個節點

(4)然後到了使用B+ Tree(多路平衡查找樹)

  1. 首先你要知道什麼B+ Tree,其實他是專門爲磁盤或者其他的直接存取輔助設備設計的一種平衡查找樹,在B樹中,所有的節點都是按照鍵值的大小順序存放在同一層的葉子節點上,由各葉子節點的指針連接。

  2. 下圖的一顆B樹,是一個高度爲2,每一頁可以放4條記錄,扇出是5。
    在這裏插入圖片描述
    重要的第一點:

  3. 重要的第一點:B+ Tree有一個很大的改變就是他的每一個非葉子節點的內節點中都沒有date這個概念了,都變成了key,因爲他的date都放在了葉子節點上,這樣的一個最大的好處就利用了局部性原理(當一個數據被用到時,其附近的數據也通常會馬上被使用)與磁盤預讀的特性(磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向後讀取一定長度的數據【這個一定的長度就是一個節點的大小設置爲16K】放入內存)

  4. 接着上面的:預讀的長度一般爲頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割爲連續的大小相等的塊,每個存儲塊稱爲一頁(在許多操作系統中,頁得大小通常爲4k),主存和磁盤以頁爲單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置並向後連續讀取一頁或幾頁載入內存中,然後異常返回,程序繼續運行。

  5. 重要的第二點:由於上面我們說的預讀原理,因爲B+ Tree中節點的內節點無 data 域,其實就是因爲沒有date域了,但是每次IO的頁的大小是固定的,但是B+Tree中沒有了date域,那麼肯定每次IO讀取若干個塊塊中包含的Key域的值肯定更多啊,B+樹單次磁盤 IO 的信息量大於B樹,從這點來看B+樹相對B樹磁盤 IO 次數少。

  6. 數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設爲等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。

  7. 爲了達到這個目的在實際實現B-Tree還需要使用如下技巧:每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。

重要的第二點:

  1. B+Tree中因爲數據都在葉子節點,所以每次查詢的時間複雜度是固定的,因爲穩定性保證了
  2. 而且葉子節點之間都是鏈表的結構,所以B+ Tree也是可以支持範圍查詢的,而B樹每個節點 key 和 data 在一起,則無法區間查找。

參考索引:http://blog.codinglabs.org/articles/theory-of-mysql-index.html
局部性原理文章: https://blog.csdn.net/wwh578867817/article/details/50493940

到了這裏相必你已經徹底知道了爲什麼使用B+ Tree來作爲MySQL索引的數據結構了吧

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