欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL用B+樹(shù)作為索引結(jié)構(gòu)有什么好處

 更新時(shí)間:2021年01月12日 15:04:07   作者:程序員白楠楠  
這篇文章主要介紹了MySQL用B+樹(shù)作為索引結(jié)構(gòu)有什么好處,幫助大家更好的理解和使用MySQL 索引,感興趣的朋友可以了解下

前言

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

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

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

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

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

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

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

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

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

三、紅黑樹(shù):樹(shù)太高

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

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

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

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

四、B樹(shù):為磁盤(pán)而生

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

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

  • 每個(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樹(shù)的定義,主要是對(duì)非葉結(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)量和記錄數(shù)量的限制。

下圖是一個(gè)3階B樹(shù)的例子:

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

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

五、B+樹(shù)

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

  • B樹(shù)中每個(gè)節(jié)點(diǎn)(包括葉節(jié)點(diǎn)和非葉節(jié)點(diǎn))都存儲(chǔ)真實(shí)的數(shù)據(jù),B+樹(shù)中只有葉子節(jié)點(diǎn)存儲(chǔ)真實(shí)的數(shù)據(jù),非葉節(jié)點(diǎn)只存儲(chǔ)鍵。在MySQL中,這里所說(shuō)的真實(shí)數(shù)據(jù),可能是行的全部數(shù)據(jù)(如Innodb的聚簇索引),也可能只是行的主鍵(如Innodb的輔助索引),或者是行所在的地址(如MyIsam的非聚簇索引)。
  • B樹(shù)中一條記錄只會(huì)出現(xiàn)一次,不會(huì)重復(fù)出現(xiàn),而B(niǎo)+樹(shù)的鍵則可能重復(fù)重現(xiàn)——一定會(huì)在葉節(jié)點(diǎn)出現(xiàn),也可能在非葉節(jié)點(diǎn)重復(fù)出現(xiàn)。
  • B+樹(shù)的葉節(jié)點(diǎn)之間通過(guò)雙向鏈表鏈接。
  • B樹(shù)中的非葉節(jié)點(diǎn),記錄數(shù)比子節(jié)點(diǎn)個(gè)數(shù)少1;而B(niǎo)+樹(shù)中記錄數(shù)與子節(jié)點(diǎn)個(gè)數(shù)相同。

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

  • **更少的IO次數(shù):**B+樹(shù)的非葉節(jié)點(diǎn)只包含鍵,而不包含真實(shí)數(shù)據(jù),因此每個(gè)節(jié)點(diǎn)存儲(chǔ)的記錄個(gè)數(shù)比B數(shù)多很多(即階m更大),因此B+樹(shù)的高度更低,訪問(wèn)時(shí)所需要的IO次數(shù)更少。此外,由于每個(gè)節(jié)點(diǎn)存儲(chǔ)的記錄數(shù)更多,所以對(duì)訪問(wèn)局部性原理的利用更好,緩存命中率更高。
  • **更適于范圍查詢(xún):**在B樹(shù)中進(jìn)行范圍查詢(xún)時(shí),首先找到要查找的下限,然后對(duì)B樹(shù)進(jìn)行中序遍歷,直到找到查找的上限;而B(niǎo)+樹(shù)的范圍查詢(xún),只需要對(duì)鏈表進(jìn)行遍歷即可。
  • **更穩(wěn)定的查詢(xún)效率:**B樹(shù)的查詢(xún)時(shí)間復(fù)雜度在1到樹(shù)高之間(分別對(duì)應(yīng)記錄在根節(jié)點(diǎn)和葉節(jié)點(diǎn)),而B(niǎo)+樹(shù)的查詢(xún)復(fù)雜度則穩(wěn)定為樹(shù)高,因?yàn)樗袛?shù)據(jù)都在葉節(jié)點(diǎn)。

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

六、感受B+樹(shù)的威力

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

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

  • 對(duì)于非葉節(jié)點(diǎn),記錄只包含索引的鍵和指向下一層節(jié)點(diǎn)的指針。假設(shè)每個(gè)非葉節(jié)點(diǎn)頁(yè)面存儲(chǔ)1000條記錄,則每條記錄大約占用16字節(jié);當(dāng)索引是整型或較短的字符串時(shí),這個(gè)假設(shè)是合理的。延伸一下,我們經(jīng)常聽(tīng)到建議說(shuō)索引列長(zhǎng)度不應(yīng)過(guò)大,原因就在這里:索引列太長(zhǎng),每個(gè)節(jié)點(diǎn)包含的記錄數(shù)太少,會(huì)導(dǎo)致樹(shù)太高,索引的效果會(huì)大打折扣,而且索引還會(huì)浪費(fèi)更多的空間。
  • 對(duì)于葉節(jié)點(diǎn),記錄包含了索引的鍵和值(值可能是行的主鍵、一行完整數(shù)據(jù)等,具體見(jiàn)前文),數(shù)據(jù)量更大。這里假設(shè)每個(gè)葉節(jié)點(diǎn)頁(yè)面存儲(chǔ)100條記錄(實(shí)際上,當(dāng)索引為聚簇索引時(shí),這個(gè)數(shù)字可能不足100;當(dāng)索引為輔助索引時(shí),這個(gè)數(shù)字可能遠(yuǎn)大于100;可以根據(jù)實(shí)際情況進(jìn)行估算)。

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

七、總結(jié)

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

  1. 二叉查找樹(shù)(BST):解決了排序的基本問(wèn)題,但是由于無(wú)法保證平衡,可能退化為鏈表;
  2. 平衡二叉樹(shù)(AVL):通過(guò)旋轉(zhuǎn)解決了平衡的問(wèn)題,但是旋轉(zhuǎn)操作效率太低;
  3. 紅黑樹(shù):通過(guò)舍棄嚴(yán)格的平衡和引入紅黑節(jié)點(diǎn),解決了AVL旋轉(zhuǎn)效率過(guò)低的問(wèn)題,但是在磁盤(pán)等場(chǎng)景下,樹(shù)仍然太高,IO次數(shù)太多
  4. B樹(shù):通過(guò)將二叉樹(shù)改為多路平衡查找樹(shù),解決了樹(shù)過(guò)高的問(wèn)題;
  5. B+樹(shù):在B樹(shù)的基礎(chǔ)上,將非葉節(jié)點(diǎn)改造為不存儲(chǔ)數(shù)據(jù)的純索引節(jié)點(diǎn),進(jìn)一步降低了樹(shù)的高度;此外將葉節(jié)點(diǎn)使用指針連接成鏈表,范圍查詢(xún)更加高效。

以上就是MySQL用B+樹(shù)作為索引結(jié)構(gòu)有什么好處的詳細(xì)內(nèi)容,更多關(guān)于MySQL B+樹(shù)索引結(jié)構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mysql觸發(fā)器trigger實(shí)例詳解

    mysql觸發(fā)器trigger實(shí)例詳解

    MySQL好像從5.0.2版本就開(kāi)始支持觸發(fā)器的功能了,本次博客就來(lái)介紹一下觸發(fā)器,首先還是談下概念性的東西吧,需要的朋友可以參考下
    2021-03-03
  • Mysql復(fù)合主鍵和聯(lián)合主鍵的區(qū)別解析

    Mysql復(fù)合主鍵和聯(lián)合主鍵的區(qū)別解析

    這篇文章主要介紹了Mysql復(fù)合主鍵和聯(lián)合主鍵的區(qū)別,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • MySQL?Innodb索引機(jī)制詳細(xì)介紹

    MySQL?Innodb索引機(jī)制詳細(xì)介紹

    這篇文章介紹了MySQL?Innodb索引數(shù)據(jù)結(jié)構(gòu)工作原理。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • 一文帶你了解如何用MySQL通配符實(shí)現(xiàn)過(guò)濾功能

    一文帶你了解如何用MySQL通配符實(shí)現(xiàn)過(guò)濾功能

    本文章將介紹什么是通配符、如何使用通配符以及怎樣使用LIKE操作符進(jìn)行通配搜索,以便對(duì)數(shù)據(jù)進(jìn)行復(fù)雜過(guò)濾,感興趣的小伙伴跟著小編一起來(lái)學(xué)習(xí)吧
    2023-07-07
  • MySQL事務(wù)的四種特性總結(jié)

    MySQL事務(wù)的四種特性總結(jié)

    事務(wù)就是一組DML語(yǔ)句組成,這些語(yǔ)句在邏輯上存在相關(guān)性,這一組DML語(yǔ)句要么全部成功,要么全部失敗,是一個(gè)整體,一個(gè) MySQL 數(shù)據(jù)庫(kù),可不止你一個(gè)事務(wù)在運(yùn)行,所以一個(gè)完整的事務(wù),絕對(duì)不是簡(jiǎn)單的 sql 集合,本文就給大家總結(jié)一下MySQL事務(wù)的四種特性
    2023-08-08
  • MySQL 在創(chuàng)建和刪除用戶時(shí)出現(xiàn)的ERROR 1396 (HY000)錯(cuò)誤問(wèn)題解決

    MySQL 在創(chuàng)建和刪除用戶時(shí)出現(xiàn)的ERROR 1396 (HY000)錯(cuò)誤問(wèn)題解決

    MySQL作為流行的數(shù)據(jù)庫(kù)系統(tǒng),涉及用戶管理時(shí)可能遇到ERROR1396錯(cuò)誤,該錯(cuò)誤發(fā)生在嘗試創(chuàng)建已存在的用戶或刪除不存在的用戶時(shí),解決方法包括檢查用戶存在性或選擇不同用戶名,此外,MySQL提供了創(chuàng)建和授權(quán)用戶的便捷工具,注意使用FLUSH PRIVILEGES命令使授權(quán)生效
    2024-09-09
  • MySQL rand函數(shù)實(shí)現(xiàn)隨機(jī)數(shù)的方法

    MySQL rand函數(shù)實(shí)現(xiàn)隨機(jī)數(shù)的方法

    在mysql中,使用隨機(jī)數(shù)寫(xiě)一個(gè)語(yǔ)句能一下更新幾百條MYSQL數(shù)據(jù)嗎?答案是肯定的,使用MySQL rand函數(shù),就可以使現(xiàn)在隨機(jī)數(shù)
    2016-09-09
  • MySQL中的常用函數(shù)

    MySQL中的常用函數(shù)

    這篇文章主要介紹了MySQL中的常用函數(shù)的相關(guān)資料,需要的朋友可以參考下
    2016-08-08
  • MySQL建表和增添改查操作代碼

    MySQL建表和增添改查操作代碼

    這篇文章主要介紹了MySQL建表和增添改查操作代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-03-03
  • 關(guān)于MySQL死鎖問(wèn)題的深入分析

    關(guān)于MySQL死鎖問(wèn)題的深入分析

    這篇文章主要給大家介紹了關(guān)于MySQL死鎖問(wèn)題的深入分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11

最新評(píng)論