深入理解MySQL索引底層實(shí)現(xiàn)原理丨技術(shù)干貨

一侈玄、索引的本質(zhì)

MySQL官方對(duì)索引的定義為:索引(Index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。提取句子主干举农,就可以得到索引的本質(zhì):索引是數(shù)據(jù)結(jié)構(gòu)。

我們知道腌且,數(shù)據(jù)庫(kù)查詢是數(shù)據(jù)庫(kù)的最主要功能之一梗肝。我們都希望查詢數(shù)據(jù)的速度能盡可能的快,因此數(shù)據(jù)庫(kù)系統(tǒng)的設(shè)計(jì)者會(huì)從查詢算法的角度進(jìn)行優(yōu)化铺董。最基本的查詢算法當(dāng)然是順序查找(linear search)巫击,這種復(fù)雜度為O(n)的算法在數(shù)據(jù)量很大時(shí)顯然是糟糕的,好在計(jì)算機(jī)科學(xué)的發(fā)展提供了很多更優(yōu)秀的查找算法精续,例如二分查找(binary search)坝锰、二叉樹(shù)查找(binary tree search)等。如果稍微分析一下會(huì)發(fā)現(xiàn)重付,每種查找算法都只能應(yīng)用于特定的數(shù)據(jù)結(jié)構(gòu)之上什黑,例如二分查找要求被檢索數(shù)據(jù)有序,而二叉樹(shù)查找只能應(yīng)用于二叉查找樹(shù)上堪夭,但是數(shù)據(jù)本身的組織結(jié)構(gòu)不可能完全滿足各種數(shù)據(jù)結(jié)構(gòu)(例如,理論上不可能同時(shí)將兩列都按順序進(jìn)行組織)拣凹,所以森爽,在數(shù)據(jù)之外,數(shù)據(jù)庫(kù)系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu)嚣镜,這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù)爬迟,這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法。這種數(shù)據(jù)結(jié)構(gòu)菊匿,就是索引付呕。

看一個(gè)例子:

上圖展示了一種可能的索引方式。左邊是數(shù)據(jù)表跌捆,一共有兩列七條記錄徽职,最左邊的是數(shù)據(jù)記錄的物理地址(注意邏輯上相鄰的記錄在磁盤(pán)上也并不是一定物理相鄰的)。為了加快Col2的查找佩厚,可以維護(hù)一個(gè)右邊所示的二叉查找樹(shù)姆钉,每個(gè)節(jié)點(diǎn)分別包含索引鍵值和一個(gè)指向?qū)?yīng)數(shù)據(jù)記錄物理地址的指針,這樣就可以運(yùn)用二叉查找在O(logn2)O(log2n)的復(fù)雜度內(nèi)獲取到相應(yīng)數(shù)據(jù)抄瓦。

雖然這是一個(gè)貨真價(jià)實(shí)的索引潮瓶,但是實(shí)際的數(shù)據(jù)庫(kù)系統(tǒng)幾乎沒(méi)有使用二叉查找樹(shù)或其進(jìn)化品種紅黑樹(shù)(red-black tree)實(shí)現(xiàn)的,原因會(huì)在下文介紹钙姊。

二毯辅、二叉排序樹(shù)

在介紹B樹(shù)之前,先來(lái)看另一棵神奇的樹(shù)——二叉排序樹(shù)(Binary Sort Tree)煞额,首先它是一棵樹(shù)思恐,“二叉”這個(gè)描述已經(jīng)很明顯了沾谜,就是樹(shù)上的一根樹(shù)枝開(kāi)兩個(gè)叉,于是遞歸下來(lái)就是二叉樹(shù)了(下圖所示)壁袄,而這棵樹(shù)上的節(jié)點(diǎn)是已經(jīng)排好序的类早,具體的排序規(guī)則如下

  • 若左子樹(shù)不空,則左子樹(shù)上所有節(jié)點(diǎn)的值均小于它的根節(jié)點(diǎn)的值
  • 若右子樹(shù)不空嗜逻,則右字?jǐn)?shù)上所有節(jié)點(diǎn)的值均大于它的根節(jié)點(diǎn)的值
  • 它的左涩僻、右子樹(shù)也分別為二叉排序數(shù)(遞歸定義)

從圖中可以看出,二叉排序樹(shù)組織數(shù)據(jù)時(shí)栈顷,用于查找是比較方便的逆日,因?yàn)槊看谓?jīng)過(guò)一次節(jié)點(diǎn)時(shí),最多可以減少一半的可能萄凤,不過(guò)極端情況會(huì)出現(xiàn)所有節(jié)點(diǎn)都位于同一側(cè)室抽,直觀上看就是一條直線,那么這種查詢的效率就比較低了靡努,因此需要對(duì)二叉樹(shù)左右子樹(shù)的高度進(jìn)行平衡化處理坪圾,于是就有了平衡二叉樹(shù)(Balenced Binary Tree)。

所謂“平衡”惑朦,說(shuō)的是這棵樹(shù)的各個(gè)分支的高度是均勻的兽泄,它的左子樹(shù)和右子樹(shù)的高度之差絕對(duì)值小于1,這樣就不會(huì)出現(xiàn)一條支路特別長(zhǎng)的情況漾月。于是病梢,在這樣的平衡樹(shù)中進(jìn)行查找時(shí),總共比較節(jié)點(diǎn)的次數(shù)不超過(guò)樹(shù)的高度梁肿,這就確保了查詢的效率(時(shí)間復(fù)雜度為O(logn))

三蜓陌、B樹(shù)

還是直接看圖比較清楚,圖中所示吩蔑,B樹(shù)事實(shí)上是一種平衡的多叉查找樹(shù)钮热,也就是說(shuō)最多可以開(kāi)m個(gè)叉(m>=2),我們稱之為m階b樹(shù)烛芬,為了體現(xiàn)本博客的良心之處霉旗,不同于其他地方都能看到2階B樹(shù),這里特意畫(huà)了一棵5階B樹(shù) 蛀骇。

總的來(lái)說(shuō)厌秒,m階B樹(shù)滿足以下條件

  • 每個(gè)節(jié)點(diǎn)至多可以擁有m棵子樹(shù)。
  • 根節(jié)點(diǎn)擅憔,只有至少有2個(gè)節(jié)點(diǎn)(要么極端情況鸵闪,就是一棵樹(shù)就一個(gè)根節(jié)點(diǎn),單細(xì)胞生物暑诸,即是根蚌讼,也是葉辟灰,也是樹(shù))。
  • 非根非葉的節(jié)點(diǎn)至少有的Ceil(m/2)個(gè)子樹(shù)(Ceil表示向上取整篡石,圖中5階B樹(shù)芥喇,每個(gè)節(jié)點(diǎn)至少有3個(gè)子樹(shù),也就是至少有3個(gè)叉)凰萨。
  • 非葉節(jié)點(diǎn)中的信息包括[n,A0,K1,A1,K2,A2,…,Kn,An]继控,,其中n表示該節(jié)點(diǎn)中保存的關(guān)鍵字個(gè)數(shù)胖眷,K為關(guān)鍵字且Ki<Ki+1武通,A為指向子樹(shù)根節(jié)點(diǎn)的指針。
  • 從根到葉子的每一條路徑都有相同的長(zhǎng)度珊搀,也就是說(shuō)冶忱,葉子節(jié)在相同的層,并且這些節(jié)點(diǎn)不帶信息境析,實(shí)際上這些節(jié)點(diǎn)就表示找不到指定的值囚枪,也就是指向這些節(jié)點(diǎn)的指針為空。
  • B樹(shù)的查詢過(guò)程和二叉排序樹(shù)比較類似劳淆,從根節(jié)點(diǎn)依次比較每個(gè)結(jié)點(diǎn)眶拉,因?yàn)槊總€(gè)節(jié)點(diǎn)中的關(guān)鍵字和左右子樹(shù)都是有序的,所以只要比較節(jié)點(diǎn)中的關(guān)鍵字憔儿,或者沿著指針就能很快地找到指定的關(guān)鍵字,如果查找失敗放可,則會(huì)返回葉子節(jié)點(diǎn)谒臼,即空指針。

例如查詢圖中字母表中的K

  • 從根節(jié)點(diǎn)P開(kāi)始耀里,K的位置在P之前蜈缤,進(jìn)入左側(cè)指針。
  • 左子樹(shù)中冯挎,依次比較C底哥、F、J房官、M趾徽,發(fā)現(xiàn)K在J和M之間。
  • 沿著J和M之間的指針翰守,繼續(xù)訪問(wèn)子樹(shù)孵奶,并依次進(jìn)行比較,發(fā)現(xiàn)第一個(gè)關(guān)鍵字K即為指定查找的值蜡峰。

B樹(shù)搜索的簡(jiǎn)單偽算法如下:

BTree_Search(node, key) {
    if(node == null) return null;
    foreach(node.key)
    {
        if(node.key[i] == key) return node.data[i];
        if(node.key[i] > key) return BTree_Search(point[i]->node);
    }
    return BTree_Search(point[i+1]->node);
}
data = BTree_Search(root, my_key);

B樹(shù)的特點(diǎn)可以總結(jié)為如下

  • 關(guān)鍵字集合分布在整顆樹(shù)中了袁。
  • 任何一個(gè)關(guān)鍵字出現(xiàn)且只出現(xiàn)在一個(gè)節(jié)點(diǎn)中朗恳。
  • 搜索有可能在非葉子節(jié)點(diǎn)結(jié)束。
  • 其搜索性能等價(jià)于在關(guān)鍵字集合內(nèi)做一次二分查找载绿。
  • B樹(shù)在插入刪除新的數(shù)據(jù)記錄會(huì)破壞B-Tree的性質(zhì)粥诫,因?yàn)樵诓迦雱h除時(shí),需要對(duì)樹(shù)進(jìn)行一個(gè)分裂崭庸、合并怀浆、轉(zhuǎn)移等操作以保持B-Tree性質(zhì)。

四冀自、Plus版 — B+樹(shù)

作為B樹(shù)的加強(qiáng)版揉稚,B+樹(shù)與B樹(shù)的差異在于

有n棵子樹(shù)的節(jié)點(diǎn)含有n個(gè)關(guān)鍵字(也有認(rèn)為是n-1個(gè)關(guān)鍵字)。

所有的關(guān)鍵字全部存儲(chǔ)在葉子節(jié)點(diǎn)上熬粗,且葉子節(jié)點(diǎn)本身根據(jù)關(guān)鍵字自小而大順序連接搀玖。

非葉子節(jié)點(diǎn)可以看成索引部分,節(jié)點(diǎn)中僅含有其子樹(shù)(根節(jié)點(diǎn))中的最大(或最凶つ拧)關(guān)鍵字灌诅。

B+樹(shù)的查找過(guò)程,與B樹(shù)類似含末,只不過(guò)查找時(shí)猜拾,如果在非葉子節(jié)點(diǎn)上的關(guān)鍵字等于給定值,并不終止佣盒,而是繼續(xù)沿著指針直到葉子節(jié)點(diǎn)位置挎袜。因此在B+樹(shù),不管查找成功與否肥惭,每次查找都是走了一條從根到葉子節(jié)點(diǎn)的路徑盯仪。

B+樹(shù)的特性如下

  • 所有關(guān)鍵字都存儲(chǔ)在葉子節(jié)上,且鏈表中的關(guān)鍵字恰好是有序的蜜葱。
  • 不可能非葉子節(jié)點(diǎn)命中返回全景。
  • 非葉子節(jié)點(diǎn)相當(dāng)于葉子節(jié)點(diǎn)的索引,葉子節(jié)點(diǎn)相當(dāng)于是存儲(chǔ)(關(guān)鍵字)數(shù)據(jù)的數(shù)據(jù)層牵囤。
  • 更適合文件索引系統(tǒng)爸黄。

五、帶有順序訪問(wèn)指針的B+Tree

一般在數(shù)據(jù)庫(kù)系統(tǒng)或文件系統(tǒng)中使用的B+Tree結(jié)構(gòu)都在經(jīng)典B+Tree的基礎(chǔ)上進(jìn)行了優(yōu)化揭鳞,增加了順序訪問(wèn)指針炕贵。

如上圖所示,在B+Tree的每個(gè)葉子節(jié)點(diǎn)增加一個(gè)指向相鄰葉子節(jié)點(diǎn)的指針野崇,就形成了帶有順序訪問(wèn)指針的B+Tree鲁驶。做這個(gè)優(yōu)化的目的是為了提高區(qū)間訪問(wèn)的性能,例如圖4中如果要查詢key為從18到49的所有數(shù)據(jù)記錄舞骆,當(dāng)找到18后钥弯,只需順著節(jié)點(diǎn)和指針順序遍歷就可以一次性訪問(wèn)到所有數(shù)據(jù)節(jié)點(diǎn)径荔,極大提到了區(qū)間查詢效率。

六脆霎、MySQL為什么使用B樹(shù)(B+樹(shù))

紅黑樹(shù)等數(shù)據(jù)結(jié)構(gòu)也可以用來(lái)實(shí)現(xiàn)索引总处,但是文件系統(tǒng)以及數(shù)據(jù)庫(kù)系統(tǒng)普遍采用B樹(shù)或者B+樹(shù),這一節(jié)將結(jié)合計(jì)算機(jī)組成原理相關(guān)知識(shí)討論B-/+Tree作為索引的理論基礎(chǔ)睛蛛。

一般來(lái)說(shuō)鹦马,索引本身也很大,不可能全部存儲(chǔ)在內(nèi)存中忆肾,因此索引往往以索引文件的形式存儲(chǔ)在磁盤(pán)上荸频。這樣的話,索引查找過(guò)程中就要產(chǎn)生磁盤(pán)I/O消耗客冈,相對(duì)于內(nèi)存存取旭从,I/O存取的消耗要高幾個(gè)數(shù)量級(jí),所以評(píng)價(jià)一個(gè)數(shù)據(jù)結(jié)構(gòu)作為索引的優(yōu)劣最重要的指標(biāo)就是在查找過(guò)程中磁盤(pán)I/O操作次數(shù)的漸進(jìn)復(fù)雜度场仲。換句話說(shuō)和悦,索引的結(jié)構(gòu)組織要盡量減少查找過(guò)程中磁盤(pán)I/O的存取次數(shù)。下面先介紹內(nèi)存和磁盤(pán)存取原理渠缕,然后再結(jié)合這些原理分析B-/+Tree作為索引的效率鸽素。

1. 主存存取原理

目前計(jì)算機(jī)使用的主存基本都是隨機(jī)讀寫(xiě)存儲(chǔ)器(RAM),現(xiàn)代RAM的結(jié)構(gòu)和存取原理比較復(fù)雜亦鳞,這里本文拋卻具體差別馍忽,抽象出一個(gè)十分簡(jiǎn)單的存取模型來(lái)說(shuō)明RAM的工作原理。

從抽象角度看燕差,主存是一系列的存儲(chǔ)單元組成的矩陣遭笋,每個(gè)存儲(chǔ)單元存儲(chǔ)固定大小的數(shù)據(jù)。每個(gè)存儲(chǔ)單元有唯一的地址谁不,現(xiàn)代主存的編址規(guī)則比較復(fù)雜,這里將其簡(jiǎn)化成一個(gè)二維地址:通過(guò)一個(gè)行地址和一個(gè)列地址可以唯一定位到一個(gè)存儲(chǔ)單元徽诲。上圖展示了一個(gè)4 x 4的主存模型刹帕。

主存的存取過(guò)程如下

  • 當(dāng)系統(tǒng)需要讀取主存時(shí),則將地址信號(hào)放到地址總線上傳給主存谎替,主存讀到地址信號(hào)后偷溺,解析信號(hào)并定位到指定存儲(chǔ)單元,然后將此存儲(chǔ)單元數(shù)據(jù)放到數(shù)據(jù)總線上钱贯,供其它部件讀取挫掏。

  • 寫(xiě)主存的過(guò)程類似,系統(tǒng)將要寫(xiě)入單元地址和數(shù)據(jù)分別放在地址總線和數(shù)據(jù)總線上秩命,主存讀取兩個(gè)總線的內(nèi)容尉共,做相應(yīng)的寫(xiě)操作褒傅。

這里可以看出,主存存取的時(shí)間僅與存取次數(shù)呈線性關(guān)系袄友,因?yàn)椴淮嬖跈C(jī)械操作殿托,兩次存取的數(shù)據(jù)的“距離”不會(huì)對(duì)時(shí)間有任何影響,例如剧蚣,先取A0再取A1和先取A0再取D3的時(shí)間消耗是一樣的支竹。

2. 磁盤(pán)存取原理

上文說(shuō)過(guò),索引一般以文件形式存儲(chǔ)在磁盤(pán)上鸠按,索引檢索需要磁盤(pán)I/O操作礼搁。與主存不同,磁盤(pán)I/O存在機(jī)械運(yùn)動(dòng)耗費(fèi)目尖,因此磁盤(pán)I/O的時(shí)間消耗是巨大的馒吴。

下圖是磁盤(pán)的整體結(jié)構(gòu)示意圖:

一個(gè)磁盤(pán)由大小相同且同軸的圓形盤(pán)片組成,磁盤(pán)可以轉(zhuǎn)動(dòng)(各個(gè)磁盤(pán)必須同步轉(zhuǎn)動(dòng))卑雁。在磁盤(pán)的一側(cè)有磁頭支架募书,磁頭支架固定了一組磁頭,每個(gè)磁頭負(fù)責(zé)存取一個(gè)磁盤(pán)的內(nèi)容测蹲。磁頭不能轉(zhuǎn)動(dòng)莹捡,但是可以沿磁盤(pán)半徑方向運(yùn)動(dòng)(實(shí)際是斜切向運(yùn)動(dòng)),每個(gè)磁頭同一時(shí)刻也必須是同軸的扣甲,即從正上方向下看篮赢,所有磁頭任何時(shí)候都是重疊的(不過(guò)目前已經(jīng)有多磁頭獨(dú)立技術(shù),可不受此限制)琉挖。

下圖是磁盤(pán)結(jié)構(gòu)的示意圖:

盤(pán)片被劃分成一系列同心環(huán)启泣,圓心是盤(pán)片中心,每個(gè)同心環(huán)叫做一個(gè)磁道示辈,所有半徑相同的磁道組成一個(gè)柱面寥茫。磁道被沿半徑線劃分成一個(gè)個(gè)小的段,每個(gè)段叫做一個(gè)扇區(qū)矾麻,每個(gè)扇區(qū)是磁盤(pán)的最小存儲(chǔ)單元纱耻。為了簡(jiǎn)單起見(jiàn),我們下面假設(shè)磁盤(pán)只有一個(gè)盤(pán)片和一個(gè)磁頭险耀。

當(dāng)需要從磁盤(pán)讀取數(shù)據(jù)時(shí)弄喘,系統(tǒng)會(huì)將數(shù)據(jù)邏輯地址傳給磁盤(pán),磁盤(pán)的控制電路按照尋址邏輯將邏輯地址翻譯成物理地址甩牺,即確定要讀的數(shù)據(jù)在哪個(gè)磁道蘑志,哪個(gè)扇區(qū)。為了讀取這個(gè)扇區(qū)的數(shù)據(jù),需要將磁頭放到這個(gè)扇區(qū)上方急但,為了實(shí)現(xiàn)這一點(diǎn)澎媒,磁頭需要移動(dòng)對(duì)準(zhǔn)相應(yīng)磁道,這個(gè)過(guò)程叫做尋道羊始,所耗費(fèi)時(shí)間叫做尋道時(shí)間旱幼,然后磁盤(pán)旋轉(zhuǎn)將目標(biāo)扇區(qū)旋轉(zhuǎn)到磁頭下,這個(gè)過(guò)程耗費(fèi)的時(shí)間叫做旋轉(zhuǎn)時(shí)間突委。

3. 局部性原理與磁盤(pán)預(yù)讀

由于存儲(chǔ)介質(zhì)的特性柏卤,磁盤(pán)本身存取就比主存慢很多,再加上機(jī)械運(yùn)動(dòng)耗費(fèi)匀油,磁盤(pán)的存取速度往往是主存的幾百分分之一缘缚,因此為了提高效率,要盡量減少磁盤(pán)I/O敌蚜。為了達(dá)到這個(gè)目的桥滨,磁盤(pán)往往不是嚴(yán)格按需讀取,而是每次都會(huì)預(yù)讀弛车,即使只需要一個(gè)字節(jié)齐媒,磁盤(pán)也會(huì)從這個(gè)位置開(kāi)始,順序向后讀取一定長(zhǎng)度的數(shù)據(jù)放入內(nèi)存纷跛。這樣做的理論依據(jù)是計(jì)算機(jī)科學(xué)中著名的局部性原理:

當(dāng)一個(gè)數(shù)據(jù)被用到時(shí)喻括,其附近的數(shù)據(jù)也通常會(huì)馬上被使用。

所以贫奠,程序運(yùn)行期間所需要的數(shù)據(jù)通常應(yīng)當(dāng)比較集中唬血。

由于磁盤(pán)順序讀取的效率很高(不需要尋道時(shí)間,只需很少的旋轉(zhuǎn)時(shí)間)唤崭,因此對(duì)于具有局部性的程序來(lái)說(shuō)拷恨,預(yù)讀可以提高I/O效率。

預(yù)讀的長(zhǎng)度一般為頁(yè)(page)的整倍數(shù)谢肾。頁(yè)是計(jì)算機(jī)管理存儲(chǔ)器的邏輯塊腕侄,硬件及操作系統(tǒng)往往將主存和磁盤(pán)存儲(chǔ)區(qū)分割為連續(xù)的大小相等的塊,每個(gè)存儲(chǔ)塊稱為一頁(yè)(在許多操作系統(tǒng)中芦疏,頁(yè)得大小通常為4k)冕杠,主存和磁盤(pán)以頁(yè)為單位交換數(shù)據(jù)。當(dāng)程序要讀取的數(shù)據(jù)不在主存中時(shí)眯分,會(huì)觸發(fā)一個(gè)缺頁(yè)異常拌汇,此時(shí)系統(tǒng)會(huì)向磁盤(pán)發(fā)出讀盤(pán)信號(hào)柒桑,磁盤(pán)會(huì)找到數(shù)據(jù)的起始位置并向后連續(xù)讀取一頁(yè)或幾頁(yè)載入內(nèi)存中弊决,然后異常返回,程序繼續(xù)運(yùn)行。

4. B-/+Tree索引的性能分析

到這里終于可以分析B-/+Tree索引的性能了飘诗。

上文說(shuō)過(guò)一般使用磁盤(pán)I/O次數(shù)評(píng)價(jià)索引結(jié)構(gòu)的優(yōu)劣与倡。先從B-Tree分析,根據(jù)B-Tree的定義昆稿,可知檢索一次最多需要訪問(wèn)h個(gè)節(jié)點(diǎn)纺座。數(shù)據(jù)庫(kù)系統(tǒng)的設(shè)計(jì)者巧妙利用了磁盤(pán)預(yù)讀原理,將一個(gè)節(jié)點(diǎn)的大小設(shè)為等于一個(gè)頁(yè)溉潭,這樣每個(gè)節(jié)點(diǎn)只需要一次I/O就可以完全載入净响。為了達(dá)到這個(gè)目的,在實(shí)際實(shí)現(xiàn)B-Tree還需要使用如下技巧:

每次新建節(jié)點(diǎn)時(shí)喳瓣,直接申請(qǐng)一個(gè)頁(yè)的空間馋贤,這樣就保證一個(gè)節(jié)點(diǎn)物理上也存儲(chǔ)在一個(gè)頁(yè)里,加之計(jì)算機(jī)存儲(chǔ)分配都是按頁(yè)對(duì)齊的畏陕,就實(shí)現(xiàn)了一個(gè)node只需一次I/O配乓。

B-Tree中一次檢索最多需要h-1次I/O(根節(jié)點(diǎn)常駐內(nèi)存),漸進(jìn)復(fù)雜度為O(h)=O(logdN)O(h)=O(logdN)惠毁。一般實(shí)際應(yīng)用中犹芹,出度d是非常大的數(shù)字,通常超過(guò)100鞠绰,因此h非常醒 (通常不超過(guò)3)。(h表示樹(shù)的高度 & 出度d表示的是樹(shù)的度洞豁,即樹(shù)中各個(gè)節(jié)點(diǎn)的度的最大值)

綜上所述盐固,用B-Tree作為索引結(jié)構(gòu)效率是非常高的。

而紅黑樹(shù)這種結(jié)構(gòu)丈挟,h明顯要深的多刁卜。由于邏輯上很近的節(jié)點(diǎn)(父子)物理上可能很遠(yuǎn),無(wú)法利用局部性曙咽,所以紅黑樹(shù)的I/O漸進(jìn)復(fù)雜度也為O(h)蛔趴,效率明顯比B-Tree差很多。

上文還說(shuō)過(guò)例朱,B+Tree更適合外存索引孝情,原因和內(nèi)節(jié)點(diǎn)出度d有關(guān)。從上面分析可以看到洒嗤,d越大索引的性能越好箫荡,而出度的上限取決于節(jié)點(diǎn)內(nèi)key和data的大小:

dmax=floor(pagesize/(keysize+datasize+pointsize))

floor表示向下取整渔隶。由于B+Tree內(nèi)節(jié)點(diǎn)去掉了data域羔挡,因此可以擁有更大的出度洁奈,擁有更好的性能。

七绞灼、MySQL索引實(shí)現(xiàn)

在MySQL中利术,索引屬于存儲(chǔ)引擎級(jí)別的概念,不同存儲(chǔ)引擎對(duì)索引的實(shí)現(xiàn)方式是不同的低矮,本文主要討論MyISAM和InnoDB兩個(gè)存儲(chǔ)引擎的索引實(shí)現(xiàn)方式印叁。

1. MyISAM索引實(shí)現(xiàn)

MyISAM引擎使用B+Tree作為索引結(jié)構(gòu),葉節(jié)點(diǎn)的data域存放的是數(shù)據(jù)記錄的地址军掂。下圖是MyISAM索引的原理圖:

這里設(shè)表一共有三列轮蜕,假設(shè)我們以Col1為主鍵,則上圖是一個(gè)MyISAM表的主索引(Primary key)示意蝗锥〕λ洌可以看出MyISAM的索引文件僅僅保存數(shù)據(jù)記錄的地址。在MyISAM中玛追,主索引和輔助索引(Secondary key)在結(jié)構(gòu)上沒(méi)有任何區(qū)別税课,只是主索引要求key是唯一的,而輔助索引的key可以重復(fù)痊剖。如果我們?cè)贑ol2上建立一個(gè)輔助索引韩玩,則此索引的結(jié)構(gòu)如下圖所示:

同樣也是一棵B+樹(shù),data域保存數(shù)據(jù)記錄的地址陆馁。因此找颓,MyISAM中索引檢索的算法為首先按照B+Tree搜索算法搜索索引,如果指定的Key存在叮贩,則取出其data域的值击狮,然后以data域的 值為地址,讀取相應(yīng)數(shù)據(jù)記錄益老。

MyISAM的索引方式也叫做“非聚集”的彪蓬,之所以這么稱呼是為了與InnoDB的聚集索引區(qū)分。

2. InnoDB索引實(shí)現(xiàn)

雖然InnoDB也使用B+Tree作為索引結(jié)構(gòu)捺萌,但具體實(shí)現(xiàn)方式卻與MyISAM截然不同档冬。

第一個(gè)重大區(qū)別是InnoDB的數(shù)據(jù)文件本身就是索引文件。從上文知道桃纯,MyISAM索引文件和數(shù)據(jù)文件是分離的酷誓,索引文件僅保存數(shù)據(jù)記錄的地址。而在InnoDB中态坦,表數(shù)據(jù)文件本身就是按B+Tree組織的一個(gè)索引結(jié)構(gòu)盐数,這棵樹(shù)的葉節(jié)點(diǎn)data域保存了完整的數(shù)據(jù)記錄。這個(gè)索引的key是數(shù)據(jù)表的主鍵伞梯,因此InnoDB表數(shù)據(jù)文件本身就是主索引玫氢。

上圖是InnoDB主索引(同時(shí)也是數(shù)據(jù)文件)的示意圖着茸,可以看到葉節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄。這種索引叫做聚集索引琐旁。因?yàn)镮nnoDB的數(shù)據(jù)文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒(méi)有)猜绣,如果沒(méi)有顯式指定灰殴,則MySQL系統(tǒng)會(huì)自動(dòng)選擇一個(gè)可以唯一標(biāo)識(shí)數(shù)據(jù)記錄的列作為主鍵,如果不存在這種列掰邢,則MySQL自動(dòng)為InnoDB表生成一個(gè)隱含字段作為主鍵牺陶,這個(gè)字段長(zhǎng)度為6個(gè)字節(jié),類型為長(zhǎng)整型辣之。

第二個(gè)與MyISAM索引的不同是InnoDB的輔助索引data域存儲(chǔ)相應(yīng)記錄主鍵的值而不是地址掰伸。換句話說(shuō),InnoDB的所有輔助索引都引用主鍵作為data域怀估。例如狮鸭,上圖為定義在Col3上的一個(gè)輔助索引:

這里以英文字符的ASCII碼作為比較準(zhǔn)則。聚集索引這種實(shí)現(xiàn)方式使得按主鍵的搜索十分高效多搀,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵歧蕉,然后用主鍵到主索引中檢索獲得記錄。

了解不同存儲(chǔ)引擎的索引實(shí)現(xiàn)方式對(duì)于正確使用和優(yōu)化索引都非常有幫助康铭,例如知道了InnoDB的索引實(shí)現(xiàn)后惯退,就很容易明白為什么不建議使用過(guò)長(zhǎng)的字段作為主鍵,因?yàn)樗休o助索引都引用主索引从藤,過(guò)長(zhǎng)的主索引會(huì)令輔助索引變得過(guò)大催跪。再例如,用非單調(diào)的字段作為主鍵在InnoDB中不是個(gè)好主意夷野,因?yàn)镮nnoDB數(shù)據(jù)文件本身是一棵B+Tree懊蒸,非單調(diào)的主鍵會(huì)造成在插入新記錄時(shí)數(shù)據(jù)文件為了維持B+Tree的特性而頻繁的分裂調(diào)整,十分低效悯搔,而使用自增字段作為主鍵則是一個(gè)很好的選擇榛鼎。

Java_蘇先生:專注于Java開(kāi)發(fā)技術(shù)的研究與知識(shí)分享!
————END————

  • 點(diǎn)贊(感謝)
  • ...
  • 轉(zhuǎn)發(fā)(感謝)
  • ...
  • 關(guān)注(感謝)
  • ...
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鳖孤,一起剝皮案震驚了整個(gè)濱河市者娱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苏揣,老刑警劉巖黄鳍,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異平匈,居然都是意外死亡框沟,警方通過(guò)查閱死者的電腦和手機(jī)藏古,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)忍燥,“玉大人拧晕,你說(shuō)我怎么就攤上這事∶仿ⅲ” “怎么了厂捞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)队丝。 經(jīng)常有香客問(wèn)我靡馁,道長(zhǎng),這世上最難降的妖魔是什么机久? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任臭墨,我火速辦了婚禮,結(jié)果婚禮上膘盖,老公的妹妹穿的比我還像新娘胧弛。我一直安慰自己,他們只是感情好侠畔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布叶圃。 她就那樣靜靜地躺著,像睡著了一般践图。 火紅的嫁衣襯著肌膚如雪掺冠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天码党,我揣著相機(jī)與錄音德崭,去河邊找鬼。 笑死揖盘,一個(gè)胖子當(dāng)著我的面吹牛眉厨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兽狭,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼憾股,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了箕慧?” 一聲冷哼從身側(cè)響起服球,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎颠焦,沒(méi)想到半個(gè)月后斩熊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伐庭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年粉渠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了分冈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霸株,死狀恐怖雕沉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情去件,我是刑警寧澤坡椒,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站箫攀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幼衰。R本人自食惡果不足惜靴跛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渡嚣。 院中可真熱鬧梢睛,春花似錦、人聲如沸识椰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腹鹉。三九已至藏畅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間功咒,已是汗流浹背愉阎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留力奋,地道東北人榜旦。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像景殷,于是被迫代替她去往敵國(guó)和親溅呢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容