0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MySQL為什么選擇B+樹作為索引結(jié)構(gòu)?

jf_ro2CN3Fa ? 來源:編程迷思 ? 2023-07-20 11:28 ? 次閱讀

前言

在MySQL中,無論是Innodb還是MyIsam,都使用了B+樹作索引結(jié)構(gòu)(這里不考慮hash等其他索引)。本文將從最普通的二叉查找樹開始,逐步說明各種樹解決的問題以及面臨的新問題,從而說明MySQL為什么選擇B+樹作為索引結(jié)構(gòu)。

一、二叉查找樹(BST):不平衡

二叉查找樹(BST,Binary Search Tree),也叫二叉排序樹,在二叉樹的基礎(chǔ)上需要滿足:任意節(jié)點(diǎn)的左子樹上所有節(jié)點(diǎn)值不大于根節(jié)點(diǎn)的值,任意節(jié)點(diǎn)的右子樹上所有節(jié)點(diǎn)值不小于根節(jié)點(diǎn)的值。如下是一顆BST(圖片來源)。

80c3f282-269e-11ee-962d-dac502259ad0.jpg

當(dāng)需要快速查找時(shí),將數(shù)據(jù)存儲(chǔ)在BST是一種常見的選擇,因?yàn)榇藭r(shí)查詢時(shí)間取決于樹高,平均時(shí)間復(fù)雜度是O(lgn)。然而BST 可能長(zhǎng)歪而變得不平衡,如下圖所示(圖片來源),此時(shí)BST退化為鏈表,時(shí)間復(fù)雜度退化為O(n)。

為了解決這個(gè)問題,引入了平衡二叉樹。

80e0be30-269e-11ee-962d-dac502259ad0.jpg

二、平衡二叉樹(AVL):旋轉(zhuǎn)耗時(shí)

AVL樹是嚴(yán)格的平衡二叉樹,所有節(jié)點(diǎn)的左右子樹高度差不能超過1;AVL樹查找、插入和刪除在平均和最壞情況下都是O(lgn)。

AVL實(shí)現(xiàn)平衡的關(guān)鍵在于旋轉(zhuǎn)操作:插入和刪除可能破壞二叉樹的平衡,此時(shí)需要通過一次或多次樹旋轉(zhuǎn)來重新平衡這個(gè)樹。當(dāng)插入數(shù)據(jù)時(shí),最多只需要1次旋轉(zhuǎn)(單旋轉(zhuǎn)或雙旋轉(zhuǎn));但是當(dāng)刪除數(shù)據(jù)時(shí),會(huì)導(dǎo)致樹失衡,AVL需要維護(hù)從被刪除節(jié)點(diǎn)到根節(jié)點(diǎn)這條路徑上所有節(jié)點(diǎn)的平衡,旋轉(zhuǎn)的量級(jí)為O(lgn)。

由于旋轉(zhuǎn)的耗時(shí),AVL樹在刪除數(shù)據(jù)時(shí)效率很低 ;在刪除操作較多時(shí),維護(hù)平衡所需的代價(jià)可能高于其帶來的好處,因此AVL實(shí)際使用并不廣泛。

三、紅黑樹:樹太高

與AVL樹相比,紅黑樹并不追求嚴(yán)格的平衡,而是大致的平衡:只是確保從根到葉子的最長(zhǎng)的可能路徑不多于最短的可能路徑的兩倍長(zhǎng)。從實(shí)現(xiàn)來看,紅黑樹最大的特點(diǎn)是每個(gè)節(jié)點(diǎn)都屬于兩種顏色(紅色或黑色)之一,且節(jié)點(diǎn)顏色的劃分需要滿足特定的規(guī)則(具體規(guī)則略)。紅黑樹示例如下(圖片來源):

80f4d7e4-269e-11ee-962d-dac502259ad0.jpg

與AVL樹相比,紅黑樹的查詢效率會(huì)有所下降,這是因?yàn)闃涞钠胶庑宰儾?,高度更高。但紅黑樹的刪除效率大大提高了,因?yàn)榧t黑樹同時(shí)引入了顏色,當(dāng)插入或刪除數(shù)據(jù)時(shí),只需要進(jìn)行O(1)次數(shù)的旋轉(zhuǎn)以及變色就能保證基本的平衡,不需要像AVL樹進(jìn)行O(lgn)次數(shù)的旋轉(zhuǎn)??偟膩碚f,紅黑樹的統(tǒng)計(jì)性能高于AVL。

因此,在實(shí)際應(yīng)用中,AVL樹的使用相對(duì)較少,而紅黑樹的使用非常廣泛。例如,Java中的TreeMap使用紅黑樹存儲(chǔ)排序鍵值對(duì);Java8中的HashMap使用鏈表+紅黑樹解決哈希沖突問題(當(dāng)沖突節(jié)點(diǎn)較少時(shí),使用鏈表,當(dāng)沖突節(jié)點(diǎn)較多時(shí),使用紅黑樹)。

對(duì)于數(shù)據(jù)在內(nèi)存中的情況(如上述的TreeMap和HashMap),紅黑樹的表現(xiàn)是非常優(yōu)異的。但是對(duì)于數(shù)據(jù)在磁盤等輔助存儲(chǔ)設(shè)備中的情況(如** **MySQL****等數(shù)據(jù)庫(kù)),紅黑樹并不擅長(zhǎng),因?yàn)榧t黑樹長(zhǎng)得還是太高了 。當(dāng)數(shù)據(jù)在磁盤中時(shí),磁盤IO會(huì)成為最大的性能瓶頸,設(shè)計(jì)的目標(biāo)應(yīng)該是盡量減少IO次數(shù);而樹的高度越高,增刪改查所需要的IO次數(shù)也越多,會(huì)嚴(yán)重影響性能。

四、B樹:為磁盤而生

B樹也稱B-樹(其中-不是減號(hào)),是為磁盤等輔存設(shè)備設(shè)計(jì)的多路平衡查找樹,與二叉樹相比,B樹的每個(gè)非葉節(jié)點(diǎn)可以有多個(gè)子樹。 因此,當(dāng)總節(jié)點(diǎn)數(shù)量相同時(shí),B樹的高度遠(yuǎn)遠(yuǎn)小于AVL樹和紅黑樹(B樹是一顆“矮胖子”),磁盤IO次數(shù)大大減少。

定義B樹最重要的概念是階數(shù)(Order),對(duì)于一顆m階B樹,需要滿足以下條件:

每個(gè)節(jié)點(diǎn)最多包含 m 個(gè)子節(jié)點(diǎn)。

如果根節(jié)點(diǎn)包含子節(jié)點(diǎn),則至少包含 2 個(gè)子節(jié)點(diǎn);除根節(jié)點(diǎn)外,每個(gè)非葉節(jié)點(diǎn)至少包含 m/2 個(gè)子節(jié)點(diǎn)。

擁有 k 個(gè)子節(jié)點(diǎn)的非葉節(jié)點(diǎn)將包含 k - 1 條記錄。

所有葉節(jié)點(diǎn)都在同一層中。

可以看出,B樹的定義,主要是對(duì)非葉結(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)量和記錄數(shù)量的限制。

下圖是一個(gè)3階B樹的例子(圖片來源):

81089932-269e-11ee-962d-dac502259ad0.jpg

B樹的優(yōu)勢(shì)除了樹高小,還有對(duì)訪問局部性原理的利用。所謂局部性原理,是指當(dāng)一個(gè)數(shù)據(jù)被使用時(shí),其附近的數(shù)據(jù)有較大概率在短時(shí)間內(nèi)被使用。B樹將鍵相近的數(shù)據(jù)存儲(chǔ)在同一個(gè)節(jié)點(diǎn),當(dāng)訪問其中某個(gè)數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)會(huì)將該整個(gè)節(jié)點(diǎn)讀到緩存中;當(dāng)它臨近的數(shù)據(jù)緊接著被訪問時(shí),可以直接在緩存中讀取,無需進(jìn)行磁盤IO;換句話說,B樹的緩存命中率更高。

B樹在數(shù)據(jù)庫(kù)中有一些應(yīng)用,如mongodb的索引使用了B樹結(jié)構(gòu)。但是在很多數(shù)據(jù)庫(kù)應(yīng)用中,使用了是B樹的變種B+樹。

五、B+樹

B+樹也是多路平衡查找樹,其與B樹的區(qū)別主要在于:

B樹中每個(gè)節(jié)點(diǎn)(包括葉節(jié)點(diǎn)和非葉節(jié)點(diǎn))都存儲(chǔ)真實(shí)的數(shù)據(jù),B+樹中只有葉子節(jié)點(diǎn)存儲(chǔ)真實(shí)的數(shù)據(jù),非葉節(jié)點(diǎn)只存儲(chǔ)鍵。在MySQL中,這里所說的真實(shí)數(shù)據(jù),可能是行的全部數(shù)據(jù)(如Innodb的聚簇索引),也可能只是行的主鍵(如Innodb的輔助索引),或者是行所在的地址(如MyIsam的非聚簇索引)。

B樹中一條記錄只會(huì)出現(xiàn)一次,不會(huì)重復(fù)出現(xiàn),而B+樹的鍵則可能重復(fù)重現(xiàn)——一定會(huì)在葉節(jié)點(diǎn)出現(xiàn),也可能在非葉節(jié)點(diǎn)重復(fù)出現(xiàn)。

B+樹的葉節(jié)點(diǎn)之間通過雙向鏈表鏈接。

B樹中的非葉節(jié)點(diǎn),記錄數(shù)比子節(jié)點(diǎn)個(gè)數(shù)少1;而B+樹中記錄數(shù)與子節(jié)點(diǎn)個(gè)數(shù)相同。

由此,B+樹與B樹相比,有以下優(yōu)勢(shì):

更少的IO次數(shù):B+樹的非葉節(jié)點(diǎn)只包含鍵,而不包含真實(shí)數(shù)據(jù),因此每個(gè)節(jié)點(diǎn)存儲(chǔ)的記錄個(gè)數(shù)比B數(shù)多很多(即階m更大),因此B+樹的高度更低,訪問時(shí)所需要的IO次數(shù)更少。此外,由于每個(gè)節(jié)點(diǎn)存儲(chǔ)的記錄數(shù)更多,所以對(duì)訪問局部性原理的利用更好,緩存命中率更高。

更適于范圍查詢:在B樹中進(jìn)行范圍查詢時(shí),首先找到要查找的下限,然后對(duì)B樹進(jìn)行中序遍歷,直到找到查找的上限;而B+樹的范圍查詢,只需要對(duì)鏈表進(jìn)行遍歷即可。

更穩(wěn)定的查詢效率:B樹的查詢時(shí)間復(fù)雜度在1到樹高之間(分別對(duì)應(yīng)記錄在根節(jié)點(diǎn)和葉節(jié)點(diǎn)),而B+樹的查詢復(fù)雜度則穩(wěn)定為樹高,因?yàn)樗袛?shù)據(jù)都在葉節(jié)點(diǎn)。

B+樹也存在劣勢(shì):由于鍵會(huì)重復(fù)出現(xiàn),因此會(huì)占用更多的空間。但是與帶來的性能優(yōu)勢(shì)相比,空間劣勢(shì)往往可以接受,因此B+樹的在數(shù)據(jù)庫(kù)中的使用比B樹更加廣泛。

六、感受B+樹的威力

前面說到,B樹/B+樹與紅黑樹等二叉樹相比,最大的優(yōu)勢(shì)在于樹高更小。實(shí)際上,對(duì)于Innodb的B+索引來說,樹的高度一般在2-4層。下面來進(jìn)行一些具體的估算。

樹的高度是由階數(shù)決定的,階數(shù)越大樹越矮;而階數(shù)的大小又取決于每個(gè)節(jié)點(diǎn)可以存儲(chǔ)多少條記錄。Innodb中每個(gè)節(jié)點(diǎn)使用一個(gè)頁(page),頁的大小為16KB,其中元數(shù)據(jù)只占大約128字節(jié)左右(包括文件管理頭信息、頁面頭信息等等),大多數(shù)空間都用來存儲(chǔ)數(shù)據(jù)。

對(duì)于非葉節(jié)點(diǎn),記錄只包含索引的鍵和指向下一層節(jié)點(diǎn)的指針。假設(shè)每個(gè)非葉節(jié)點(diǎn)頁面存儲(chǔ)1000條記錄,則每條記錄大約占用16字節(jié);當(dāng)索引是整型或較短的字符串時(shí),這個(gè)假設(shè)是合理的。延伸一下,我們經(jīng)常聽到建議說索引列長(zhǎng)度不應(yīng)過大,原因就在這里:索引列太長(zhǎng),每個(gè)節(jié)點(diǎn)包含的記錄數(shù)太少,會(huì)導(dǎo)致樹太高,索引的效果會(huì)大打折扣,而且索引還會(huì)浪費(fèi)更多的空間。

對(duì)于葉節(jié)點(diǎn),記錄包含了索引的鍵和值(值可能是行的主鍵、一行完整數(shù)據(jù)等,具體見前文),數(shù)據(jù)量更大。這里假設(shè)每個(gè)葉節(jié)點(diǎn)頁面存儲(chǔ)100條記錄(實(shí)際上,當(dāng)索引為聚簇索引時(shí),這個(gè)數(shù)字可能不足100;當(dāng)索引為輔助索引時(shí),這個(gè)數(shù)字可能遠(yuǎn)大于100;可以根據(jù)實(shí)際情況進(jìn)行估算)。

對(duì)于一顆3層B+樹,第一層(根節(jié)點(diǎn))有1個(gè)頁面,可以存儲(chǔ)1000條記錄;第二層有1000個(gè)頁面,可以存儲(chǔ)10001000條記錄;第三層(葉節(jié)點(diǎn))有10001000個(gè)頁面,每個(gè)頁面可以存儲(chǔ)100條記錄,因此可以存儲(chǔ)10001000100條記錄,即1億條。而對(duì)于二叉樹,存儲(chǔ)1億條記錄則需要26層左右。

七、總結(jié)

最后,總結(jié)一下各種樹解決的問題以及面臨的新問題:

二叉查找樹(BST):解決了排序的基本問題,但是由于無法保證平衡,可能退化為鏈表;

平衡二叉樹(AVL):通過旋轉(zhuǎn)解決了平衡的問題,但是旋轉(zhuǎn)操作效率太低;

紅黑樹:通過舍棄嚴(yán)格的平衡和引入紅黑節(jié)點(diǎn),解決了AVL旋轉(zhuǎn)效率過低的問題,但是在磁盤等場(chǎng)景下,樹仍然太高,IO次數(shù)太多;

B樹:通過將二叉樹改為多路平衡查找樹,解決了樹過高的問題;

B+樹:在B樹的基礎(chǔ)上,將非葉節(jié)點(diǎn)改造為不存儲(chǔ)數(shù)據(jù)的純索引節(jié)點(diǎn),進(jìn)一步降低了樹的高度;此外將葉節(jié)點(diǎn)使用指針連接成鏈表,范圍查詢更加高效。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • AVL
    AVL
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    10025
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    789

    瀏覽量

    26283
  • 二叉樹
    +關(guān)注

    關(guān)注

    0

    文章

    74

    瀏覽量

    12283
  • MYSQL數(shù)據(jù)庫(kù)

    關(guān)注

    0

    文章

    95

    瀏覽量

    9348
  • BST
    BST
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    5846

原文標(biāo)題:圖文詳解紅黑樹,還有誰不會(huì)??

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Mysql優(yōu)化選擇最佳索引規(guī)則

    索引的目的在于提高查詢效率,其功能可類比字典,通過該索引可以查詢到我們想要查詢的信息,因此,選擇建立好的索引十分重要,以下是為Mysql優(yōu)化
    發(fā)表于 07-06 15:13

    MySQL數(shù)據(jù)庫(kù)索引的底層是怎么實(shí)現(xiàn)的

    二叉B,B+這4種數(shù)據(jù)結(jié)構(gòu),以及為啥選用B+
    發(fā)表于 07-28 15:30

    基于B+的動(dòng)態(tài)數(shù)據(jù)持有性證明方案

    針對(duì)云存儲(chǔ)環(huán)境下的數(shù)據(jù)持有性證明( PDP)方案效率較低、不能很好支持全動(dòng)態(tài)更新的問題,設(shè)計(jì)了一種基于B+的動(dòng)態(tài)數(shù)據(jù)持有性證明方案。該方案引入雙線性對(duì)技術(shù)和數(shù)據(jù)版本表,支持用戶進(jìn)行數(shù)據(jù)塊級(jí)的細(xì)粒度
    發(fā)表于 11-30 17:14 ?0次下載
    基于<b class='flag-5'>B+</b><b class='flag-5'>樹</b>的動(dòng)態(tài)數(shù)據(jù)持有性證明方案

    基于KD和R的多維索引結(jié)構(gòu)

    針對(duì)云存儲(chǔ)系統(tǒng)大多基于鍵值對(duì) key,value模型存儲(chǔ)數(shù)據(jù),多維查詢需要對(duì)整個(gè)數(shù)據(jù)集進(jìn)行完全掃描,查詢效率較低的問題,提出了一種基于KD和R的多維索引結(jié)構(gòu)(簡(jiǎn)稱KD-R
    發(fā)表于 01-25 15:13 ?0次下載
    基于KD<b class='flag-5'>樹</b>和R<b class='flag-5'>樹</b>的多維<b class='flag-5'>索引</b><b class='flag-5'>結(jié)構(gòu)</b>

    MySQL索引使用原則

    一般來說, MySQL 中的 B-Tree 索引的物理文件大多都是以 Balance Tree 的結(jié)構(gòu)來存儲(chǔ)的,也就是所有實(shí)際需要的數(shù)據(jù)都存放于 Tree 的 Leaf Node(葉子
    的頭像 發(fā)表于 02-11 15:17 ?2664次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>索引</b>使用原則

    MySQL索引的使用問題

    MySQL 在LIKE進(jìn)行模糊匹配的時(shí)候又是如何利用索引的呢?3、MySQL 到底在怎么樣的情況下能夠利用索引進(jìn)行排序?今天,我將會(huì)用一個(gè)模型,把這些問題都一一解答,讓你對(duì)
    的頭像 發(fā)表于 01-06 16:13 ?1532次閱讀

    關(guān)于MySQL ORDER BY的詳解

    回答一些常見的問題(下文僅討論InnoDB存儲(chǔ)引擎)。 2 索引掃描排序和文件排序(filesort)簡(jiǎn)介 我們知道InnoDB存儲(chǔ)引擎以B+作為
    的頭像 發(fā)表于 02-08 11:20 ?2385次閱讀
    關(guān)于<b class='flag-5'>MySQL</b> ORDER BY的詳解

    掌握這幾種方法 你的接口查詢速度將飛速提升

    很大時(shí),大多慢查詢可以用索引解決,大多慢查詢也因?yàn)?b class='flag-5'>索引不合理而產(chǎn)生。 MySQL 索引基于 B+
    的頭像 發(fā)表于 07-06 14:38 ?1713次閱讀

    對(duì) B+ 索引MySQL 中的認(rèn)識(shí)

    概述 本質(zhì):數(shù)據(jù)庫(kù)維護(hù)某種數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù) 索引取舍原則:索引結(jié)構(gòu)組織要盡量減少查找過程中磁盤I/O的存取次數(shù) B
    的頭像 發(fā)表于 11-08 11:11 ?1206次閱讀
    對(duì) <b class='flag-5'>B+</b> <b class='flag-5'>樹</b>與<b class='flag-5'>索引</b>在 <b class='flag-5'>MySQL</b> 中的認(rèn)識(shí)

    Mysql索引為什么使用B+?

    比方說我們想要查找行數(shù)據(jù)5。會(huì)先從頂層頁的record們?nèi)胧帧ecord里包含了主鍵id和頁號(hào)(頁地址)。關(guān)注黃色的箭頭,向左最小id是1,向右最小id是7。那id=5的數(shù)據(jù)如果存在,那必定在左邊箭頭。于是順著的record的頁地址就到了6號(hào)數(shù)據(jù)頁里,再判斷id=5>4,所以肯定在右邊的數(shù)據(jù)頁里,于是加載105號(hào)數(shù)據(jù)頁。
    的頭像 發(fā)表于 06-08 16:34 ?607次閱讀
    <b class='flag-5'>Mysql</b><b class='flag-5'>索引</b>為什么使用<b class='flag-5'>B+</b><b class='flag-5'>樹</b>?

    MySQL高級(jí)進(jìn)階:索引優(yōu)化

    MySQL官方對(duì)于索引的定義:索引是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)
    的頭像 發(fā)表于 06-11 11:13 ?503次閱讀
    <b class='flag-5'>MySQL</b>高級(jí)進(jìn)階:<b class='flag-5'>索引</b>優(yōu)化

    id的機(jī)制不同在mysql索引結(jié)構(gòu)以及優(yōu)缺點(diǎn)

    1.4.效率測(cè)試結(jié)果 二、使用uuid和自增id的索引結(jié)構(gòu)對(duì)比 2.1.使用自增id的內(nèi)部結(jié)構(gòu) 2.2.使用uuid的索引內(nèi)部結(jié)構(gòu) 2.3
    的頭像 發(fā)表于 06-30 10:19 ?716次閱讀
    id的機(jī)制不同在<b class='flag-5'>mysql</b>的<b class='flag-5'>索引</b><b class='flag-5'>結(jié)構(gòu)</b>以及優(yōu)缺點(diǎn)

    MySQL索引的常用知識(shí)點(diǎn)

    索引結(jié)構(gòu)B+ 索引其實(shí)是一種數(shù)據(jù)結(jié)構(gòu) 注意B+
    的頭像 發(fā)表于 09-30 16:43 ?374次閱讀

    索引是什么意思 優(yōu)缺點(diǎn)有哪些

    的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫(kù)表中數(shù)據(jù)。索引的實(shí)現(xiàn)通常使用B及其變種B+。更通俗的說
    的頭像 發(fā)表于 10-09 10:19 ?2453次閱讀

    一文了解MySQL索引機(jī)制

    的呢?一起靜下心來,耐心看完這篇文章吧,干貨不啰嗦,相信你一定會(huì)有所收獲。 一、索引模型 模型也就是數(shù)據(jù)結(jié)構(gòu),常見的三種模型分別是哈希表、有序數(shù)組和搜索。 了解MySQL的朋友已經(jīng)知
    的頭像 發(fā)表于 07-25 14:05 ?154次閱讀
    一文了解<b class='flag-5'>MySQL</b><b class='flag-5'>索引</b>機(jī)制