在MySQL中,不管是Innodb仍是MyIsam,都使用了B+樹做索引結構(這裏不考慮hash等其餘索引)。本文將從最普通的二叉查找樹開始,逐步說明各類樹解決的問題以及面臨的新問題,從而說明MySQL爲何選擇B+樹做爲索引結構。html
1、二叉查找樹(BST):不平衡mongodb
5、B+樹性能
6、感覺B+樹的威力spa
7、總結.net
二叉查找樹(BST,Binary Search Tree),也叫二叉排序樹,在二叉樹的基礎上須要知足:任意節點的左子樹上全部節點值不大於根節點的值,任意節點的右子樹上全部節點值不小於根節點的值。以下是一顆BST(圖片來源)。設計
當須要快速查找時,將數據存儲在BST是一種常見的選擇,由於此時查詢時間取決於樹高,平均時間複雜度是O(lgn)。然而,BST可能長歪而變得不平衡,以下圖所示(圖片來源),此時BST退化爲鏈表,時間複雜度退化爲O(n)。指針
爲了解決這個問題,引入了平衡二叉樹。
AVL樹是嚴格的平衡二叉樹,全部節點的左右子樹高度差不能超過1;AVL樹查找、插入和刪除在平均和最壞狀況下都是O(lgn)。
AVL實現平衡的關鍵在於旋轉操做:插入和刪除可能破壞二叉樹的平衡,此時須要經過一次或屢次樹旋轉來從新平衡這個樹。當插入數據時,最多隻須要1次旋轉(單旋轉或雙旋轉);可是當刪除數據時,會致使樹失衡,AVL須要維護從被刪除節點到根節點這條路徑上全部節點的平衡,旋轉的量級爲O(lgn)。
因爲旋轉的耗時,AVL樹在刪除數據時效率很低;在刪除操做較多時,維護平衡所需的代價可能高於其帶來的好處,所以AVL實際使用並不普遍。
與AVL樹相比,紅黑樹並不追求嚴格的平衡,而是大體的平衡:只是確保從根到葉子的最長的可能路徑很少於最短的可能路徑的兩倍長。從實現來看,紅黑樹最大的特色是每一個節點都屬於兩種顏色(紅色或黑色)之一,且節點顏色的劃分須要知足特定的規則(具體規則略)。紅黑樹示例以下(圖片來源):
與AVL樹相比,紅黑樹的查詢效率會有所降低,這是由於樹的平衡性變差,高度更高。但紅黑樹的刪除效率大大提升了,由於紅黑樹同時引入了顏色,當插入或刪除數據時,只須要進行O(1)次數的旋轉以及變色就能保證基本的平衡,不須要像AVL樹進行O(lgn)次數的旋轉。總的來講,紅黑樹的統計性能高於AVL。
所以,在實際應用中,AVL樹的使用相對較少,而紅黑樹的使用很是普遍。例如,Java中的TreeMap使用紅黑樹存儲排序鍵值對;Java8中的HashMap使用鏈表+紅黑樹解決哈希衝突問題(當衝突節點較少時,使用鏈表,當衝突節點較多時,使用紅黑樹)。
對於數據在內存中的狀況(如上述的TreeMap和HashMap),紅黑樹的表現是很是優異的。可是對於數據在磁盤等輔助存儲設備中的狀況(如MySQL等數據庫),紅黑樹並不擅長,由於紅黑樹長得仍是過高了。當數據在磁盤中時,磁盤IO會成爲最大的性能瓶頸,設計的目標應該是儘可能減小IO次數;而樹的高度越高,增刪改查所須要的IO次數也越多,會嚴重影響性能。
B樹也稱B-樹(其中-不是減號),是爲磁盤等輔存設備設計的多路平衡查找樹,與二叉樹相比,B樹的每一個非葉節點能夠有多個子樹。所以,當總節點數量相同時,B樹的高度遠遠小於AVL樹和紅黑樹(B樹是一顆「矮胖子」),磁盤IO次數大大減小。
定義B樹最重要的概念是階數(Order),對於一顆m階B樹,須要知足如下條件:
能夠看出,B樹的定義,主要是對非葉結點的子節點數量和記錄數量的限制。
下圖是一個3階B樹的例子(圖片來源):
B樹的優點除了樹高小,還有對訪問局部性原理的利用。所謂局部性原理,是指當一個數據被使用時,其附近的數據有較大機率在短期內被使用。B樹將鍵相近的數據存儲在同一個節點,當訪問其中某個數據時,數據庫會將該整個節點讀到緩存中;當它臨近的數據緊接着被訪問時,能夠直接在緩存中讀取,無需進行磁盤IO;換句話說,B樹的緩存命中率更高。
B樹在數據庫中有一些應用,如mongodb的索引使用了B樹結構。可是在不少數據庫應用中,使用了是B樹的變種B+樹。
B+樹也是多路平衡查找樹,其與B樹的區別主要在於:
由此,B+樹與B樹相比,有如下優點:
B+樹也存在劣勢:因爲鍵會重複出現,所以會佔用更多的空間。可是與帶來的性能優點相比,空間劣勢每每能夠接受,所以B+樹的在數據庫中的使用比B樹更加普遍。
前面說到,B樹/B+樹與紅黑樹等二叉樹相比,最大的優點在於樹高更小。實際上,對於Innodb的B+索引來講,樹的高度通常在2-4層。下面來進行一些具體的估算。
樹的高度是由階數決定的,階數越大樹越矮;而階數的大小又取決於每一個節點能夠存儲多少條記錄。Innodb中每一個節點使用一個頁(page),頁的大小爲16KB,其中元數據只佔大約128字節左右(包括文件管理頭信息、頁面頭信息等等),大多數空間都用來存儲數據。
對於一顆3層B+樹,第一層(根節點)有1個頁面,能夠存儲1000條記錄;第二層有1000個頁面,能夠存儲1000*1000條記錄;第三層(葉節點)有1000*1000個頁面,每一個頁面能夠存儲100條記錄,所以能夠存儲1000*1000*100條記錄,即1億條。而對於二叉樹,存儲1億條記錄則須要26層左右。
最後,總結一下各類樹解決的問題以及面臨的新問題:
1) 二叉查找樹(BST):解決了排序的基本問題,可是因爲沒法保證平衡,可能退化爲鏈表;
2) 平衡二叉樹(AVL):經過旋轉解決了平衡的問題,可是旋轉操做效率過低;
3) 紅黑樹:經過捨棄嚴格的平衡和引入紅黑節點,解決了AVL旋轉效率太低的問題,可是在磁盤等場景下,樹仍然過高,IO次數太多;
4) B樹:經過將二叉樹改成多路平衡查找樹,解決了樹太高的問題;
5) B+樹:在B樹的基礎上,將非葉節點改造爲不存儲數據的純索引節點,進一步下降了樹的高度;此外將葉節點使用指針鏈接成鏈表,範圍查詢更加高效。
《MySQL技術內幕:InnoDB存儲引擎》
《MySQL運維內參》
https://zhuanlan.zhihu.com/p/54102723
https://cloud.tencent.com/developer/article/1425604
https://blog.csdn.net/whoamiyang/article/details/51926985
https://www.jianshu.com/p/37436ed14cc6
https://blog.csdn.net/CrankZ/article/details/83301702
https://www.cnblogs.com/gaochundong/p/btree_and_bplustree.html
創做不易,若是文章對你有幫助,就點個贊、評個論唄~
創做不易,若是文章對你有幫助,就點個贊、評個論唄~
創做不易,若是文章對你有幫助,就點個贊、評個論唄~