通常說MySQL的索引,都清楚其索引主要以B+樹爲主,此外還有Hash、RTree、FullText。本文簡要說明一下MySQL的B+Tree索引,以及和其相關的二叉樹、平衡二叉樹、B-Tree,相關的知識網上不少,爲了方便本身更快、清楚的瞭解,文本聚合一些內容以及我的的一些理解。html
(1)非葉子節點只能容許最多兩個子節點存在。mysql
(2)每個非葉子節點數據分佈規則爲左邊的子節點小當前節點的值,右邊的子節點大於當前節點的值;
即二叉查找樹的特色就是任何節點的左子節點的鍵值都小於當前節點的鍵值,右子節點的鍵值都大於當前節點的鍵值。 頂端的節點稱爲根節點,沒有子節點的節點咱們稱之爲葉節點。如下圖中的圓爲二叉查找樹的節點,節點中存儲了鍵(key)和數據(data)sql
查找結點值的方法就是二分查找法:查找次數就是樹的高度。二叉查找樹能夠任意地構造 若是向一方傾斜的二叉樹是不平衡的,查詢效率就低了,二叉查找樹變成了一個鏈表。以下圖:數據庫
在上面的2張圖中,查找鍵值爲17的數據,第一張圖裏須要3次IO,第2張圖裏須要7次IO。緣由是二叉查找樹變得不平衡了,也就是高度過高了,從而致使查找效率的不穩定。爲了解決這個問題,須要保證二叉查找樹一直保持平衡,就須要用到平衡二叉樹了。 緩存
在知足二叉查找樹特性的基礎上,如不是空樹,任何一個結點的左子樹與右子樹都是平衡二叉樹,而且高度之差的絕對值不超過 1。 相似於:數據結構
關於平衡二叉樹的能夠看 什麼是平衡二叉樹(AVL)該文章說明,平衡二叉樹相比於二叉查找樹來講,查找效率更穩定,整體的查找速度也更快。須要注意的是平衡二叉樹是每一個節點只存儲一個鍵值和數據的。函數
(1)排序方式:全部節點關鍵字是按遞增次序排列,並遵循左小右大原則;性能
(2)子節點數:非葉節點的子節點數>1,且<=M ,且M>=2,空樹除外(注:M階表明一個樹節點最多有多少個查找路徑,M=M路,當M=2則是2叉樹,M=3則是3叉);spa
(3)關鍵字數:枝節點的關鍵字數量大於等於ceil(M/2)-1個且小於等於M-1個(注:ceil()是個朝正無窮方向取整的函數 如ceil(1.1)結果爲2);3d
(4)全部葉子節點均在同一層、葉子節點除了包含了關鍵字還包含了數據;
最後咱們用一個圖和一個實際的例子來理解B樹(這裏爲了理解方便我就直接用實際字母的大小來排列C>B>A)
圖中能夠看到BTree的單個節點能夠存儲多個鍵值和數據的平衡樹。和平衡二叉樹相比:
好比要存儲海量的數據,由於(平衡)二叉樹的每一個節點只存儲一個鍵值和數據的,二叉樹的節點將會很是多,高度也會及其高,當查找數據時也會進行不少次磁盤IO,查找的效率將會極低,大體的二叉樹結構以下:
爲了解決平衡二叉樹的這個弊端,須要一種單個節點能夠存儲多個鍵值和數據的平衡樹(BTree):
從上圖能夠看出,B樹相對於平衡二叉樹,每一個節點存儲了更多的鍵值(key)和數據(data),而且每一個節點擁有更多的子節點,子節點的個數通常稱爲階,上述圖中的B樹爲3階B樹,高度也會很低。 基於這個特性,B樹查找數據讀取磁盤的次數將會不多,數據的查找效率也會比平衡二叉樹高不少。
假如咱們要查找id=28的用戶信息,那麼咱們在上圖B樹中查找的流程以下: 1. 先找到根節點也就是頁1,判斷28在鍵值17和35之間,咱們那麼咱們根據頁1中的指針p2找到頁3。 2. 將28和頁3中的鍵值相比較,28在26和30之間,咱們根據頁3中的指針p2找到頁8。 3. 將28和頁8中的鍵值相比較,發現有匹配的鍵值28,鍵值28對應的用戶信息爲(28,bv)。
區別:B樹相對於平衡二叉樹的不一樣是:每一個節點包含的關鍵字增多了,特別是在B樹應用到數據庫中的時候,數據庫充分利用了磁盤塊的原理(磁盤數據存儲是採用塊的形式存儲的,每一個塊的大小爲4K,每次IO進行數據讀取時,同一個磁盤塊的數據能夠一次性讀取出來)把節點大小限制和充分使用在磁盤快大小範圍;把樹的節點關鍵字增多後樹的層級比原來的二叉樹少了,減小數據查找的次數和複雜度。
相同數量的key在B-Tree中生成的節點要遠遠少於二叉樹中的節點,相差的節點數量就等同於磁盤IO的次數。這樣到達必定數量後,性能的差別就顯現出來了。
(1)B+樹的非葉子節點不保存數據,只進行數據索引(關鍵字記錄的指針),這樣使得B+樹每一個非葉子節點所能保存的關鍵字大大增長;
(2)B+樹葉子節點保存了父節點的全部關鍵字記錄的指針,全部數據地址必需要到葉子節點才能獲取到。因此每次數據查詢的次數都同樣;
(3)B+樹葉子節點的關鍵字從小到大有序排列,左邊結尾數據都會保存右邊節點開始數據的指針;
(4)B+樹非葉子節點的子節點數=關鍵字數;
一、B+樹的層級更少:相較於B樹,B+每一個非葉子節點存儲的關鍵字數更多,樹的層級更少因此查詢數據更快;
二、B+樹查詢速度更穩定:B+全部關鍵字數據地址都存在葉子節點上,因此每次查找的次數都相同因此查詢速度要比B樹更穩定;
三、B+樹自然具有排序功能:B+樹全部的葉子節點數據構成了一個有序鏈表,在查詢大小區間的數據時候更方便,數據緊密性很高,緩存的命中率也會比B樹高。
四、B+樹全節點遍歷更快:B+樹遍歷整棵樹只須要遍歷全部的葉子節點便可,而不須要像B樹同樣須要對每一層進行遍歷,這有利於數據庫作全表掃描。
B樹相對於B+樹的優勢是:若是常常訪問的數據離根節點很近,而B樹的非葉子節點自己存有關鍵字其數據的地址,因此這種數據檢索的時候會要比B+樹快。
根據上圖咱們來看下B+樹和B樹有什麼不一樣:
1. B+Tree 非葉子節點上是不存儲數據的,僅存儲鍵值,數據存儲在同一層的葉節點,而B-Tree節點中不只存儲鍵值,也會存儲數據。之因此這麼作是由於在數據庫中頁的大小是固定的,innodb中頁的默認大小是16KB。若是不存儲數據,那麼就會存儲更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來咱們查找數據進行磁盤的IO次數有會再次減小,數據查詢的效率也會更快。另外,B+Tree的階數是等於鍵值的數量的,若是B+Tree一個節點能夠存儲1000個鍵值,那麼3層B+樹能夠存儲1000×1000×1000=10億個數據。通常根節點是常駐內存的,因此通常咱們查找10億數據,只須要2次磁盤IO。
2. 由於B+Tree索引的全部數據均存儲在葉子節點,並且數據是按照順序排列的。那麼B+樹使得範圍查找,排序查找,分組查找以及去重查找變得異常簡單。而B-Tree 由於數據分散在各個節點,要實現這一點是很不容易的。
B+Tree 中各個頁之間是經過雙向鏈表鏈接的,葉子節點中的數據是經過單向鏈表鏈接的。
其實上面的B-Tree也能夠對各個節點加上鍊表。其實這些不是它們以前的區別,是由於在mysql的innodb存儲引擎中,索引就是這樣存儲的。也就是說上圖中的B+Tree索引就是innodb中B+Tree索引真正的實現方式,準確的說應該是彙集索引。
經過上圖能夠看到,在innodb中,數據頁之間經過雙向鏈表鏈接以及葉子節點中數據之間經過單向鏈表鏈接的方式能夠找到表中全部的數據。
注意:MyISAM中的B+樹索引實現與innodb中的略有不一樣。在MyISAM中,B+樹索引的葉子節點並不存儲數據,而是存儲數據的文件地址。
B+Tree 結構是從二叉查找樹,平衡二叉樹和B-Tree這三種數據結構演化來的,他們以前的區別上面已經介紹過,如今大體的總結下,以下:
1,二叉查找樹是基於二分查找法來提升數據查找速度的二叉樹的數據結構,減小無關數據的檢索,提高了數據檢索的速度。非葉子節點只能容許最多兩個子節點存在,每個非葉子節點數據分佈規則爲左邊的子節點小當前節點的值,右邊的子節點大於當前節點的值,每一個節點只存儲一個鍵值和數據的。
2,平衡二叉樹知足二叉查找樹特性的基礎上,如不是空樹,任何一個結點的左子樹與右子樹都是平衡二叉樹,而且高度之差的絕對值不超過 1。
3,B-TreeB和平衡二叉樹不一樣,B-Tree屬於多叉樹又名平衡多路查找樹, B-Tree相對於平衡二叉樹,每一個節點存儲了更多的鍵值(key)和數據(data),而且每一個節點擁有更多的子節點。
4,B+Tree和B-Tree不一樣,B+Tree在非葉子節點上,不保存數據,只存儲鍵指針,能存儲更多的鍵值,相應的樹的階數(節點的子節點樹)就會更大,樹就會更矮更胖,如此一來咱們查找數據進行磁盤的IO次數有會再次減小,數據查詢的效率也會更快。而且B+樹索引的全部數據均存儲在葉子節點,並且數據是按照順序排列的。那麼B+Tree使得範圍查找,排序查找,分組查找以及去重查找變得異常簡單。
https://database.51cto.com/art/201911/605365.htm
https://zhuanlan.zhihu.com/p/27700617