溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引

發(fā)布時(shí)間:2021-11-30 11:04:20 來(lái)源:億速云 閱讀:175 作者:柒染 欄目:數(shù)據(jù)庫(kù)

本篇文章給大家分享的是有關(guān)MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

一、前言

為了講清楚這個(gè)問(wèn)題,阿粉先帶大家了解一下什么是索引。

我記得剛剛學(xué)習(xí)數(shù)據(jù)庫(kù)的時(shí)候,老師喜歡用書(shū)本的目錄來(lái)類比數(shù)據(jù)庫(kù)的索引,并告訴我們索引能夠像目錄一樣,讓我們更快地找到想要找到的數(shù)據(jù)。

如果是第一次接觸索引,這個(gè)比喻能夠讓我們有一個(gè)直觀的印象。但是當(dāng)深入去學(xué)習(xí)索引的時(shí)候,我們不能繼續(xù)持有索引即目錄的思想,我們要跳出來(lái)去思考索引的本質(zhì)是什么。

二、索引的本質(zhì)

在沒(méi)有索引的情況下,我們查找數(shù)據(jù)只能按照從頭到尾的順序逐行查找,每查找一行數(shù)據(jù),意味著我們要到到磁盤相應(yīng)的位置去讀取一條數(shù)據(jù)。

如果把查詢一條數(shù)據(jù)分為到磁盤中查詢和比對(duì)查詢條件兩步的話,到磁盤中查詢的時(shí)間會(huì)遠(yuǎn)遠(yuǎn)大于比對(duì)查詢條件的時(shí)間,這意味著在一次查詢中,磁盤io占用了大部分的時(shí)間。更進(jìn)一步地說(shuō),一次查詢的效率取絕于磁盤io的次數(shù),如果我們能夠在一次查詢中盡可能地降低磁盤io的次數(shù),那么我們就能加快查詢的速度。

在知道了減少磁盤io能加快查詢速度后,我們就要聚焦于如何減少磁盤io。如果按照原表逐行查詢的話,n條數(shù)據(jù)就要查詢n次,也就是O(N)的時(shí)間復(fù)雜度,為了減少磁盤io的次數(shù),我們必須用一種查詢時(shí)間復(fù)雜度更低的數(shù)據(jù)結(jié)構(gòu)來(lái)保存數(shù)據(jù)。

這種查詢時(shí)間復(fù)雜度低的數(shù)據(jù)結(jié)構(gòu),我們稱之為索引。所以通俗來(lái)說(shuō),索引其實(shí)就是某種數(shù)據(jù)結(jié)構(gòu),能充當(dāng)索引的數(shù)據(jù)結(jié)構(gòu)是多種多樣的。

三、索引的選擇

既然索引是一種便于查詢的數(shù)據(jù)結(jié)構(gòu),如果大家對(duì)數(shù)據(jù)結(jié)構(gòu)有一定了解的話,大概率會(huì)首選樹(shù)型結(jié)構(gòu)。畢竟樹(shù)型結(jié)構(gòu)普遍有著O(logN)的查詢時(shí)間復(fù)雜度,而且插入刪除數(shù)據(jù)的性能也比較平均。(可能你會(huì)說(shuō)數(shù)組,哈希表的查詢速度也很高啊,這個(gè)后面也會(huì)分析)

雖然我們都已經(jīng)知道Mysql中最常用的引擎像InnoDB和MyISAM,最終都選擇了B+樹(shù)作為索引,但是這里我還是打算從最常見(jiàn)的二叉樹(shù)開(kāi)始講起,推導(dǎo)一下為什么最終選擇了B+樹(shù)作為索引,并比較一下幾種樹(shù)型結(jié)構(gòu)在充當(dāng)索引時(shí)的優(yōu)劣。

二叉樹(shù)

最普通的二叉樹(shù)的問(wèn)題在于他不能保證O(logN)的查詢時(shí)間復(fù)雜度,我們看下面的圖:

MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引

由于插入的元素逐漸增大,元素始終在右邊進(jìn)行插入,好好的一棵二叉樹(shù)最終變成了一條“鏈表”。在這種極端的情況下,二叉樹(shù)的查詢時(shí)間復(fù)雜度不再是O(logN),而是退化為O(N),這樣顯然不符合索引的要求。

平衡二叉樹(shù)(紅黑樹(shù))

像紅黑樹(shù)這樣的平衡二叉樹(shù),無(wú)論如何插入元素,他都可以通過(guò)一些旋轉(zhuǎn)的方法調(diào)整樹(shù)的高度,使得整棵樹(shù)的查詢效率維持在O(logN),如下圖所示:

MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引

這么來(lái)說(shuō)他已經(jīng)符合了成為索引的必備條件,但是最終沒(méi)有選擇他作為索引說(shuō)明還有不足的地方。仔細(xì)看看可以發(fā)現(xiàn)平衡二叉樹(shù)的每個(gè)節(jié)點(diǎn)只有兩個(gè)孩子節(jié)點(diǎn),如果一張表的數(shù)據(jù)量特別大,整棵樹(shù)的高度也會(huì)隨之上升。一個(gè)千萬(wàn)級(jí)別的表如果用平衡二叉樹(shù)作為索引的話,樹(shù)高將會(huì)達(dá)到二十多層。這也就意味著做一次查詢需要二十多次磁盤io,這是一個(gè)不小的開(kāi)銷。

那么有沒(méi)有能在大數(shù)據(jù)量的情況下,還能保持一個(gè)較小樹(shù)高的樹(shù)型結(jié)構(gòu)呢?

B樹(shù)和B+樹(shù)

答案就是B樹(shù)。上面我們說(shuō)到了平衡二叉樹(shù)的瓶頸在于一個(gè)節(jié)點(diǎn)只有兩個(gè)孩子節(jié)點(diǎn),而B(niǎo)樹(shù)一個(gè)節(jié)點(diǎn)可以存放N個(gè)孩子節(jié)點(diǎn),這就完美解決了樹(shù)高的問(wèn)題,我們可以把B樹(shù)稱為平衡多叉樹(shù),B樹(shù)作為索引如下圖所示:

MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引

圖片來(lái)源網(wǎng)絡(luò)

但是以B樹(shù)的結(jié)構(gòu)作為索引仍有可以優(yōu)化的地方,我們先看看最終的B+樹(shù),再仔細(xì)分析B+樹(shù)在B樹(shù)的基礎(chǔ)上作了哪些改進(jìn),為什么B+樹(shù)最終能夠勝任索引的工作:

MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引

圖片來(lái)源網(wǎng)絡(luò)

從圖片中可以看到B+樹(shù)同樣是一棵多差平衡樹(shù),和B樹(shù)一樣很好地解決了樹(shù)高的問(wèn)題。

改進(jìn)點(diǎn)一:

但仔細(xì)看可以發(fā)現(xiàn),B樹(shù)的節(jié)點(diǎn)中既存儲(chǔ)索引,也存儲(chǔ)表對(duì)應(yīng)的數(shù)據(jù);而B(niǎo)+樹(shù)的非葉子節(jié)點(diǎn)是不存儲(chǔ)數(shù)據(jù)的,只存儲(chǔ)索引,數(shù)據(jù)全部存儲(chǔ)在葉子節(jié)點(diǎn)上。

為什么要做這樣的改進(jìn)?我們做一次算術(shù)就知道了。

假設(shè)樹(shù)高為2,主鍵ID為bigint類型,長(zhǎng)度為8字節(jié),節(jié)點(diǎn)指針為6字節(jié),一行數(shù)據(jù)記錄的大小為1k,一次io操作能獲得一頁(yè)16k的數(shù)據(jù)。

在索引為B+樹(shù)的情況下,根節(jié)點(diǎn)能存儲(chǔ):16k / (6 + 8) = 1170 條索引指針;到了第一層,一共能指向 1170 * 1170 =  1368900 條索引指針;到了最底一層葉子節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)能存儲(chǔ)16k / 1k = 16 條記錄,一共能存儲(chǔ) 1170 * 1170 * 16 =  21902400 條記錄

在B樹(shù)的情況下,由于非葉子節(jié)點(diǎn)使用了大量空間存儲(chǔ)數(shù)據(jù),存放的索引指針肯定就少,最終整棵樹(shù)如果想要存儲(chǔ)和B+樹(shù)一樣多的數(shù)據(jù)就必須要增加樹(shù)高,這樣一來(lái)就增加了磁盤io,所以說(shuō)B+樹(shù)作為索引的性能比B樹(shù)高。

改進(jìn)點(diǎn)二:

葉子節(jié)點(diǎn)之間使用指針連接,提高區(qū)間訪問(wèn)效率。如果我們要進(jìn)行范圍查詢,可以輕松通過(guò)B+樹(shù)葉子節(jié)點(diǎn)之間的指針進(jìn)行遍歷,減少了不必要的磁盤io。

看到這里,相信大家對(duì)為什么Mysql的常用引擎都默認(rèn)使用B+樹(shù)作為索引已經(jīng)有了初步的認(rèn)知。我們只要牢記一點(diǎn):索引是為了減少磁盤io提高查詢性能而存在的。

而數(shù)組雖然查詢的效率高,但是增加和刪除的效率低,由于記錄在增加和刪除的時(shí)候索引也得跟著維護(hù),這會(huì)導(dǎo)致大數(shù)據(jù)量的情況下,增加或刪除一條記錄效率較低。

以上就是MySQL的常用引擎為什么默認(rèn)使用B+樹(shù)作為索引,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI