阿里面試官:為什么MySQL數(shù)據(jù)庫索引選擇使用B+樹而不是跳表?
二叉查找樹
(1)二叉樹簡介:
二叉查找樹也稱為有序二叉查找樹,滿足二叉查找樹的一般性質(zhì),是指一棵空樹具有如下性質(zhì):
1、任意節(jié)點左子樹不為空,則左子樹的值均小于根節(jié)點的值;
2、任意節(jié)點右子樹不為空,則右子樹的值均大于于根節(jié)點的值;

(2)局限性及應用

大家看上圖,如果我們的根節(jié)點選擇是最小或者最大的數(shù),那么二叉查找樹就完全退化成了線性結(jié)構(gòu)。上圖中的平均查找次數(shù)為(1+2+3+4+5+5)/6=3.16次,和順序查找差不多。顯然這個二叉樹的查詢效率就很低,因此若想最大性能的構(gòu)造一個二叉查找樹,需要這個二叉樹是平衡的(這里的平衡從一個顯著的特點可以看出這一棵樹的高度比上一個輸?shù)母叨纫?,在相同?jié)點的情況下也就是不平衡),從而引出了一個新的定義-平衡二叉樹AVL。
AVL樹
(1)簡介

從上面是一個普通的平衡二叉樹,這張圖我們可以看出,任意節(jié)點的左右子樹的平衡因子差值都不會大于1。
(3)應用
1、Windows NT內(nèi)核中廣泛存在;
紅黑樹
(1)簡介
(2)性質(zhì)

(3)應用
2、著名的Linux進程調(diào)度Completely Fair Scheduler,用紅黑樹管理進程控制塊,進程的虛擬內(nèi)存區(qū)域都存儲在一顆紅黑樹上,每個虛擬地址區(qū)域都對應紅黑樹的一個節(jié)點,左指針指向相鄰的地址虛擬存儲區(qū)域,右指針指向相鄰的高地址虛擬地址空間;
3、IO多路復用epoll的實現(xiàn)采用紅黑樹組織管理sockfd,以支持快速的增刪改查;
4、Nginx中用紅黑樹管理timer,因為紅黑樹是有序的,可以很快的得到距離當前最小的定時器;
5、Java中TreeMap的實現(xiàn);
B/B+樹
說了上述的三種樹:二叉查找樹、AVL和紅黑樹,似乎我們還沒有摸到MySQL為什么要使用B+樹作為索引的實現(xiàn),不要急,接下來我們就先探討一下什么是B樹。
(1)簡介
(2)B樹的性質(zhì)
2、根結(jié)點的兒子數(shù)為[2, M];
3、除根結(jié)點以外的非葉子結(jié)點的兒子數(shù)為[M/2, M];
4、每個結(jié)點存放至少M/2-1(取上整)和至多M-1個關(guān)鍵字;(至少2個關(guān)鍵字)
5、非葉子結(jié)點的關(guān)鍵字個數(shù)=指向兒子的指針個數(shù)-1;
6、非葉子結(jié)點的關(guān)鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7、非葉子結(jié)點的指針:P[1], P[2], …, P[M];其中P[1]指向關(guān)鍵字小于K[1]的子樹,P[M]指向關(guān)鍵字大于K[M-1]的子樹,其它P[i]指向關(guān)鍵字屬于(K[i-1], K[i])的子樹;
8、所有葉子結(jié)點位于同一層;

這里只是一個簡單的B樹,在實際中B樹節(jié)點中關(guān)鍵字很多的,上面的圖中比如35節(jié)點,35代表一個key(索引),而小黑塊代表的是這個key所指向的內(nèi)容在內(nèi)存中實際的存儲位置,是一個指針。
B+樹
(1)簡介
B+樹是應文件系統(tǒng)所需而產(chǎn)生的一種B樹的變形樹(文件的目錄一級一級索引,只有最底層的葉子節(jié)點(文件)保存數(shù)據(jù))非葉子節(jié)點只保存索引,不保存實際的數(shù)據(jù),數(shù)據(jù)都保存在葉子節(jié)點中,這不就是文件系統(tǒng)文件的查找嗎?
所有的非葉子節(jié)點都可以看成索引部分!
(2)B+樹的性質(zhì)(下面提到的都是和B樹不相同的性質(zhì))
2、非葉子節(jié)點的子樹指針p[i],指向關(guān)鍵字值屬于[k[i],k[i+1]]的子樹.(B樹是開區(qū)間,也就是說B樹不允許關(guān)鍵字重復,B+樹允許重復);
3、為所有葉子節(jié)點增加一個鏈指針;
4、所有關(guān)鍵字都在葉子節(jié)點出現(xiàn)(稠密索引). (且鏈表中的關(guān)鍵字恰好是有序的);
5、非葉子節(jié)點相當于是葉子節(jié)點的索引(稀疏索引),葉子節(jié)點相當于是存儲(關(guān)鍵字)數(shù)據(jù)的數(shù)據(jù)層;
6、更適合于文件系統(tǒng);

(3)應用
B/B+樹性能分析
n個節(jié)點的平衡二叉樹的高度為H(即logn),而n個節(jié)點的B/B+樹的高度為logt((n+1)/2)+1;
若要作為內(nèi)存中的查找表,B樹卻不一定比平衡二叉樹好,尤其當m較大時更是如此。因為查找操作CPU的時間在B-樹上是O(mlogtn)=O(lgn(m/lgt)),而m/lgt>1;所以m較大時O(mlogtn)比平衡二叉樹的操作時間大得多。因此在內(nèi)存中使用B樹必須取較小的m。(通常取最小值m=3,此時B-樹中每個內(nèi)部結(jié)點可以有2或3個孩子,這種3階的B-樹稱為2-3樹)。
為什么說B+樹比B樹更適合數(shù)據(jù)庫索引?
1、 B+樹的磁盤讀寫代價更低:B+樹的內(nèi)部節(jié)點并沒有指向關(guān)鍵字具體信息的指針,因此其內(nèi)部節(jié)點相對B樹更小,如果把所有同一內(nèi)部節(jié)點的關(guān)鍵字存放在同一盤塊中,那么盤塊所能容納的關(guān)鍵字數(shù)量也越多,一次性讀入內(nèi)存的需要查找的關(guān)鍵字也就越多,相對IO讀寫次數(shù)就降低了。
2、B+樹的查詢效率更加穩(wěn)定:由于非終結(jié)點并不是最終指向文件內(nèi)容的結(jié)點,而只是葉子結(jié)點中關(guān)鍵字的索引。所以任何關(guān)鍵字的查找必須走一條從根結(jié)點到葉子結(jié)點的路。所有關(guān)鍵字查詢的路徑長度相同,導致每一個數(shù)據(jù)的查詢效率相當。
PS:我在知乎上看到有人是這樣說的,我感覺說的也挺有道理的:
B+樹的原理,基本上講完了,限于篇幅,關(guān)于MySQL為啥不用跳表?而Redis鐘情于跳表?咱們下篇再來講述。
正文結(jié)束
1.不認命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵志故事
3.從零開始搭建創(chuàng)業(yè)公司后臺技術(shù)棧
5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結(jié)果懵了...
6.IntelliJ IDEA 2019.3 首個最新訪問版本發(fā)布,新特性搶先看

