【Java面试题】MySQL索引底层为什么用到B+树
學習本章之前,先要了解紅黑樹【算法】紅黑樹原理和算法介紹,以及B樹、B+樹【算法】B樹、B+樹詳解
最近重新學習MySQL,發(fā)現(xiàn)自己一直知道MySQL索引用到了B+樹,引發(fā)思考,為什么一定要是B+樹,其他樹或者其他數(shù)據(jù)結(jié)構(gòu)不可以嗎?
為什么不是用紅黑樹
1、將大量數(shù)據(jù)全部放入內(nèi)存組織成RBT結(jié)構(gòu)顯然是不實際的。實際上,像OS中的文件目錄存儲,數(shù)據(jù)庫中的文件索引結(jié)構(gòu)的存儲…. 都不可能在內(nèi)存中建立查找結(jié)構(gòu)。數(shù)據(jù)必須在磁盤中建立好這個結(jié)構(gòu)。
2、這就涉及到磁盤的存儲原理了,操作系統(tǒng)讀寫磁盤的基本單位是扇區(qū),而文件系統(tǒng)的基本單位是簇(Cluster)(每個簇或者塊可以包括2、4、8、16、32、64…2的n次方個扇區(qū)。)。意思就是,磁盤讀寫有一個最少內(nèi)容的限制,即使我們只需要這個簇上的一個字節(jié),我們也必須把整個簇的內(nèi)容都讀完,那么現(xiàn)在就有一個悲催的事情了,如果一個父節(jié)點只有2個子結(jié)點,并不能填滿一個簇上的所有內(nèi)容,那多余的地方就浪費了,考慮到磁盤的存儲原理,B/B+樹應(yīng)運而生了。
3、由于B/B+樹分支比二叉樹多,所以相同數(shù)量的內(nèi)容,B+樹的深度更淺。B+樹的深度就代表了磁盤的 I/O 次數(shù)。
4、數(shù)據(jù)庫設(shè)計的時候B+樹有多少個分支都是按照磁盤上一個簇最多能放多少節(jié)點設(shè)計的,因此一般來說,涉及到磁盤上查詢的數(shù)據(jù)結(jié)構(gòu),都是使用B/B+樹
為什么說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ù)的查詢效率相當;
3)B+樹便于范圍查詢(最重要的原因,范圍查找是數(shù)據(jù)庫的常態(tài))
B樹在提高了IO性能的同時并沒有解決元素遍歷的我效率低下的問題,正是為了解決這個問題,B+樹應(yīng)用而生。B+樹只需要去遍歷葉子節(jié)點就可以實現(xiàn)整棵樹的遍歷。而且在數(shù)據(jù)庫中基于范圍的查詢是非常頻繁的,而B樹不支持這樣的操作或者說效率太低;
磁盤IO與預(yù)讀
計算機存儲設(shè)備一般分為兩種:內(nèi)存儲器(main memory)和外存儲器(external memory)。
內(nèi)存儲器為內(nèi)存,內(nèi)存存取速度快,但容量小,價格昂貴,而且不能長期保存數(shù)據(jù)(在不通電情況下數(shù)據(jù)會消失)。
外存儲器即為磁盤讀取,磁盤讀取數(shù)據(jù)靠的是機械運動,每次讀取數(shù)據(jù)花費的時間可以分為尋道時間、旋轉(zhuǎn)延遲、傳輸時間三個部分,尋道時間指的是磁臂移動到指定磁道所需要的時間,主流磁盤一般在5ms以下;旋轉(zhuǎn)延遲就是我們經(jīng)常聽說的磁盤轉(zhuǎn)速,比如一個磁盤7200轉(zhuǎn),表示每分鐘能轉(zhuǎn)7200次,也就是說1秒鐘能轉(zhuǎn)120次,旋轉(zhuǎn)延遲就是1/120/2 = 4.17ms;傳輸時間指的是從磁盤讀出或?qū)?shù)據(jù)寫入磁盤的時間,一般在零點幾毫秒,相對于前兩個時間可以忽略不計。那么訪問一次磁盤的時間,即一次磁盤IO的時間約等于5+4.17 = 9ms左右,聽起來還挺不錯的,但要知道一臺500 -MIPS的機器每秒可以執(zhí)行5億條指令,因為指令依靠的是電的性質(zhì),換句話說執(zhí)行一次IO的時間可以執(zhí)行40萬條指令,數(shù)據(jù)庫動輒十萬百萬乃至千萬級數(shù)據(jù),每次9毫秒的時間,顯然是個災(zāi)難。下圖是計算機硬件延遲的對比圖,供大家參考:
考慮到磁盤IO是非常高昂的操作,計算機操作系統(tǒng)做了一些優(yōu)化,當一次IO時,不光把當前磁盤地址的數(shù)據(jù),而是把相鄰的數(shù)據(jù)也都讀取到內(nèi)存緩沖區(qū)內(nèi),因為局部預(yù)讀性原理告訴我們,當計算機訪問一個地址的數(shù)據(jù)的時候,與其相鄰的數(shù)據(jù)也會很快被訪問到。每一次IO讀取的數(shù)據(jù)我們稱之為一頁(page)。具體一頁有多大數(shù)據(jù)跟操作系統(tǒng)有關(guān),一般為4k或8k,也就是我們讀取一頁內(nèi)的數(shù)據(jù)時候,實際上才發(fā)生了一次IO,這個理論對于索引的數(shù)據(jù)結(jié)構(gòu)設(shè)計非常有幫助。
事實1 : 不同容量的存儲器,訪問速度差異懸殊。
磁盤(ms級別) << 內(nèi)存(ns級別), 100000倍
若內(nèi)存訪問需要1s,則一次外存訪問需要一天
為了避免1次外存訪問,寧愿訪問內(nèi)存100次...所以將最常用的數(shù)據(jù)存儲在最快的存儲器中
事實2 : 從磁盤中讀 1 B,與讀寫 1KB 的時間成本幾乎一樣
從以上數(shù)據(jù)中可以總結(jié)出一個道理,索引查詢的數(shù)據(jù)主要受限于硬盤的I/O速度,查詢I/O次數(shù)越少,速度越快,所以B樹的結(jié)構(gòu)才應(yīng)需求而生;B樹的每個節(jié)點的元素可以視為一次I/O讀取,樹的高度表示最多的I/O次數(shù),在相同數(shù)量的總元素個數(shù)下,每個節(jié)點的元素個數(shù)越多,高度越低,查詢所需的I/O次數(shù)越少;假設(shè),一次硬盤一次I/O數(shù)據(jù)為8K,索引用int(4字節(jié))類型數(shù)據(jù)建立,理論上一個節(jié)點最多可以為2000個元素,2000*2000*2000=8000000000,80億條的數(shù)據(jù)只需3次I/O(理論值),可想而知,B樹做為索引的查詢效率有多高;
另外也可以看出同樣的總元素個數(shù),查詢效率和樹的高度密切相關(guān)
總結(jié)
以上是生活随笔為你收集整理的【Java面试题】MySQL索引底层为什么用到B+树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM相关问题
- 下一篇: lol猪妹s11出装 瑟庄妮打野天赋