国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式

這篇具有很好參考價(jià)值的文章主要介紹了MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、什么是索引

1、索引初體驗(yàn)

user_innodb這張表里有4個(gè)字段,id,name,gender,phone。
當(dāng)這張表有500萬條數(shù)據(jù),在沒有索引的name字段上執(zhí)行一條where查詢:

select * from user_innodb where name = '張三';

如果name字段上有索引呢?我們?cè)趎ame字段上面創(chuàng)建一個(gè)索引,再來執(zhí)行一下查詢:

-- name字段創(chuàng)建索引
ALTER TABLE user_innodb DROP INDEX idx_user_name;
ALTER TABLE user_innodb ADD INDEX idx_user_name (name);

我們?cè)賮韴?zhí)行一下select語句。
我們會(huì)發(fā)現(xiàn),有索引的查詢和沒有索引的查詢相比,效率竟相差幾十倍。

索引到底是什么呢?為什么可以對(duì)我們的查詢產(chǎn)生這么大的影響?創(chuàng)建索引的時(shí)候做了什么事情?

2、索引圖解

維基百科上對(duì)數(shù)據(jù)庫索引的定義:

數(shù)據(jù)庫索引,是數(shù)據(jù)庫管理系統(tǒng)(DBMS)中一個(gè)排序的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫表中數(shù)據(jù)。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

數(shù)據(jù)是以文件的形式存放在磁盤上面的,每一行數(shù)據(jù)都有它的磁盤地址。如果沒有索引的花,我們要從500萬行數(shù)據(jù)里面檢索一條數(shù)據(jù),只能依次遍歷這張表的全部數(shù)據(jù),直到找到這條數(shù)據(jù)。

但是我們有了索引之后,只需要在索引里面去檢索這條數(shù)據(jù)就行了,因?yàn)樗且环N特殊的專門用來快速檢索的數(shù)據(jù)結(jié)構(gòu),我們找到數(shù)據(jù)存放的磁盤地址以后,就可以拿到數(shù)據(jù)了。

索引就像是一本書的目錄一樣,目錄可能只有幾頁的內(nèi)容,根據(jù)拼音或者偏旁有序進(jìn)行排序的,我們可以通過目錄很快的定位到書中具體的內(nèi)容。同樣的,我們可以根據(jù)索引也可以很快的定位到這一條數(shù)據(jù)。

3、索引類型

從navicat中我們可以看到,索引包含索引名稱、索引字段、索引類型總共有三種、索引方法有兩種、注釋。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
在InnoDB中,索引類型有三種:

  • Normal 普通索引:也叫非唯一索引,是最普通的索引,沒有任何的限制。
  • Full Text 全文索引:針對(duì)比較大的數(shù)據(jù),比如我們存放的是消息內(nèi)容、一篇文章,有幾kb的數(shù)據(jù)的這種情況,如果要解決like查詢?cè)谌钠ヅ涞臅r(shí)候效率低的問題,可以創(chuàng)建全文索引。只有文本類型的字段才可以創(chuàng)建全文索引,比如char、varchar、text。
  • Unique 唯一索引:唯一索引要求鍵值不能重復(fù)。另外需要注意的是,主鍵索引是一種特殊的唯一索引,它還多了一個(gè)限制條件,要求鍵值不能為空。主鍵索引用primay key創(chuàng)建。

注!SPATIAL 空間索引:空間索引是對(duì)空間數(shù)據(jù)類型的字段建立的索引,MYSQL中的空間數(shù)據(jù)類型有4種,分別是GEOMETRY、POINT、LINESTRING、POLYGON。MYSQL使用SPATIAL關(guān)鍵字進(jìn)行擴(kuò)展,使得能夠用于創(chuàng)建正規(guī)索引類型的語法創(chuàng)建空間索引。創(chuàng)建空間索引的列,必須將其聲明為NOT NULL,空間索引只能在存儲(chǔ)引擎為MYISAM的表中創(chuàng)建。

二、索引存儲(chǔ)模型推演

1、二分查找

算法-查找算法-線性表的查找(類C語言版)

二分查找的思想,也叫折半查找,每次都把候選數(shù)據(jù)縮小了一半。如果數(shù)據(jù)已經(jīng)排過序的話,這種方式效率比較高。

所以首先,我們可以考慮使用有序數(shù)組作為索引的數(shù)據(jù)結(jié)構(gòu)。有序數(shù)組的等值查詢和比較查詢效率非常高,但是更新數(shù)據(jù)的時(shí)候會(huì)出現(xiàn)一個(gè)問題,可能要挪動(dòng)大量的數(shù)據(jù)(改變index),所以只適合存儲(chǔ)靜態(tài)的數(shù)據(jù)。

為了支持頻繁的修改,比如插入數(shù)據(jù),我們需要采用鏈表,但是鏈表的話,如果是單鏈表,它的查找效率還是不夠高。

所以,有沒有可以使用二分查找的鏈表呢?為了解決這個(gè)問題,BST(Binary Search Tree)也就是我們所說的二叉查找樹就誕生了。

2、二叉查找樹(BST Binary Search Tree)

算法-查找算法-樹表的查找(二叉排序樹、平衡二叉樹)(類C語言版)

二叉查找樹的 特點(diǎn)是什么?左子樹所有的節(jié)點(diǎn)都小于父節(jié)點(diǎn),右子樹所有的節(jié)點(diǎn)都大于父節(jié)點(diǎn)。投影到平面以后,就是一個(gè)有序的線性表。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

二叉查找樹既能夠?qū)崿F(xiàn)快速查找,又能夠?qū)崿F(xiàn)快速插入。

但是二叉查找樹有一個(gè)問題:就是它的查找耗時(shí)是和這棵樹的深度相關(guān)的,在最壞的情況下時(shí)間復(fù)雜度會(huì)退化成O(n)。

什么情況是最壞的情況呢?
還是剛才這一批數(shù)字,如果我們插入的數(shù)據(jù)剛好是有序的,它會(huì)變成鏈表(我們把這種樹叫做“斜樹”),這種情況下不能達(dá)到加快檢索速度的目的,和順序查找效率是沒有區(qū)別的。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
造成它傾斜的原因是什么呢?
因?yàn)樽笥易訕渖疃炔钐?,這棵樹的左子樹根本沒有節(jié)點(diǎn)——也就是它不夠平衡。
所以,我們有沒有左右子樹深度相差不是那么大,更加平衡的樹呢?

這個(gè)就是平衡二叉樹,叫做Balanced binary search trees,或者AVL樹(AVL是發(fā)明這個(gè)數(shù)據(jù)結(jié)構(gòu)的兩位作者的名字簡(jiǎn)寫:G.M.Adelson-Velsky和E.M.Landis)。

3、平衡二叉樹(AVL Tree)(左旋、右旋)

算法-查找算法-樹表的查找(二叉排序樹、平衡二叉樹)(類C語言版)

AVL Trees(Balanced binary search trees) 平衡二叉樹的定義:左右子樹深度差絕對(duì)值不能超過1。

比如左子樹的深度是2,右子樹的深度只能是1、2、3,這個(gè)時(shí)候我們?cè)侔错樞虿迦霐?shù)據(jù),不會(huì)變成一棵“斜樹”。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
那它的平衡是怎么做到的呢?怎么保證左右子樹的深度差不能超過1呢?

(1)平衡二叉樹的調(diào)整

舉個(gè)例子,我們依次插入1、2、3,我們注意看,當(dāng)我們插入了1、2之后,如果按照二叉查找樹的定義,3肯定是要在2的右邊的,這個(gè)時(shí)候根節(jié)點(diǎn)1的右節(jié)點(diǎn)深度會(huì)變成2,但是左節(jié)點(diǎn)的深度是0,因?yàn)樗鼪]有子節(jié)點(diǎn),所以就會(huì)違反平衡二叉樹的定義。

應(yīng)該怎么辦呢?因?yàn)樗怯夜?jié)點(diǎn)下面接一個(gè)右節(jié)點(diǎn),屬于“右-右”型,所以這個(gè)時(shí)候我們要把2提上去,這個(gè)操作叫做左旋。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

同樣的,如果我們插入7、6、5,這個(gè)時(shí)候就會(huì)變成左左型,就會(huì)發(fā)生右旋操作,把6提上去。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
所以,為了保持平衡,AVL樹在插入和更新數(shù)據(jù)的時(shí)候執(zhí)行了一系列的計(jì)算和調(diào)整的操作。

平衡的問題我們解決了,那么平衡二叉樹作為索引怎么查詢數(shù)據(jù)?

(2)平衡二叉樹的索引

在平衡二叉樹中,一個(gè)節(jié)點(diǎn),它的大小是一個(gè)固定的單位,作為索引應(yīng)該存儲(chǔ)建立索引的字段的值,叫做鍵值,比如id的值。還要存完整記錄在磁盤上的地址。由于AVL樹是二叉樹,所以還要額外地存儲(chǔ)左右子樹的指針。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
如圖所示,
第一個(gè)是索引的鍵值。比如我們?cè)趇d上面創(chuàng)建了一個(gè)索引,我在用where id = 1的條件查詢的時(shí)候就會(huì)找到索引里面的id的這個(gè)鍵值。
第二個(gè)是數(shù)據(jù)的磁盤地址,因?yàn)樗饕淖饔镁褪侨ゲ檎覕?shù)據(jù)的存放的地址。
第三個(gè),因?yàn)槭嵌鏄?,它必須還要有左子結(jié)點(diǎn)和右子節(jié)點(diǎn)的引用,這樣我們才能找到下一個(gè)結(jié)點(diǎn)。比如大于26的時(shí)候,走右邊,到下一個(gè)樹的節(jié)點(diǎn),繼續(xù)判斷。

如果是這樣存儲(chǔ)數(shù)據(jù)的話,會(huì)有什么問題呢?

(3)AVL樹用于存儲(chǔ)索引數(shù)據(jù)

首先,索引的數(shù)據(jù),是放在硬盤上的。查看數(shù)據(jù)和索引的大?。?/p>

select
concat(round(sum(data_length/1024/1024),2),'MB') AS data_len,
concat(round(sum(index_length/1024/1024),2),'MB') AS index_len
from information_schema.TABLES
where table_schema='ourea' and table_name='sys_member';

當(dāng)我們用樹的結(jié)構(gòu)來存儲(chǔ)索引的時(shí)候,訪問一個(gè)節(jié)點(diǎn)就要跟磁盤之間發(fā)生一次IO操作。InnoDB操作磁盤的最小的單位是一頁(或者叫一個(gè)磁盤塊),大小事16KB(16384字節(jié))。

那么,一個(gè)樹的節(jié)點(diǎn)必須設(shè)計(jì)成16K大小,不然就會(huì)出現(xiàn)讀不完或者讀不夠的情況。如果我們一個(gè)字節(jié)只存一個(gè)鍵值+數(shù)據(jù)+引用,例如整形的字段,可能只用了十幾個(gè)或者幾十個(gè)字節(jié),它遠(yuǎn)遠(yuǎn)達(dá)不到16K的容量。

想象一下,我們基于索引查找數(shù)據(jù)的時(shí)候,肯定是希望一次從磁盤加載很多的數(shù)據(jù)到內(nèi)存中進(jìn)行比較,這樣就可以盡快拿到完整的數(shù)據(jù),如果一個(gè)節(jié)點(diǎn)只存1個(gè)這樣的單元,就需要讀更多的節(jié)點(diǎn),發(fā)生 更多的IO操作。

如果是機(jī)械硬盤時(shí)代,每次從磁盤讀取數(shù)據(jù)需要10ms左右的尋址時(shí)間,交互次數(shù)越多,消耗的時(shí)間就越多。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
比如上面的圖,一張表里面有6條數(shù)據(jù),當(dāng)我們查詢id=66的時(shí)候,要查詢兩個(gè)子節(jié)點(diǎn),需要跟磁盤交互3次,如果我們有幾百萬數(shù)據(jù)呢?這個(gè)時(shí)間更加難以估計(jì)。

怎么解決?一就是讓每個(gè)節(jié)點(diǎn)存儲(chǔ)更多的數(shù)據(jù)。二就是節(jié)點(diǎn)上的關(guān)鍵字?jǐn)?shù)量越多,我們的指針數(shù)也越多,也就意味著可以有更多的分叉(我們把它叫做“路數(shù)”)。

因?yàn)榉植嬖蕉啵瑯涞?code>深度就會(huì)減少(根節(jié)點(diǎn)是0)。

這樣,我們的數(shù)就從原來的高瘦的樣子,變成了矮胖的樣子。這時(shí),我們的樹就不再是二叉了,而是多叉,或者叫做多路。

4、多路平衡查找樹(B Tree) (分裂、合并)

算法-B-樹、B樹、B+樹詳解

Balanced Tree就是我們說的多路平衡查找樹,叫做B Tree(B代表平衡)。

跟AVL(平衡二叉樹)一樣,B樹在枝節(jié)點(diǎn)和葉子結(jié)點(diǎn)存儲(chǔ)鍵值、數(shù)據(jù)地址、節(jié)點(diǎn)引用。

它有一個(gè)特點(diǎn):分叉數(shù)(路數(shù))永遠(yuǎn)比關(guān)鍵字?jǐn)?shù)多1。 比如我們畫的這棵樹,每個(gè)節(jié)點(diǎn)存儲(chǔ)兩個(gè)關(guān)鍵字,那么就會(huì)有三個(gè)指針指向三個(gè)子節(jié)點(diǎn)(當(dāng)然肯定不只存3個(gè)這么少)。

(1)查找實(shí)例

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
B Tree的查找規(guī)則是什么樣的呢?

比如我們要在這張表里面查找15,因?yàn)?5小于17走左邊;15大于12走右邊。在磁盤塊7里面就找到了15,只用了3次IO。

(2)B Tree保持平衡的秘訣

這確實(shí)比AVL(平衡二叉樹)效率更高,那B Tree是怎么實(shí)現(xiàn)一個(gè)節(jié)點(diǎn)存儲(chǔ)多個(gè)關(guān)鍵字,還能保持平衡的呢?跟AVL樹有什么區(qū)別?

比如Max Degree(路數(shù))是3的時(shí)候,我們插入數(shù)據(jù)1、2、3,在插入3的時(shí)候,本來應(yīng)該在第一個(gè)磁盤塊,但是如果一個(gè)節(jié)點(diǎn)有三個(gè)關(guān)鍵字的時(shí)候,意味著有4個(gè)指針,子節(jié)點(diǎn)會(huì)變成4路,所以這個(gè)時(shí)候必須進(jìn)行分裂。把中間的數(shù)據(jù)2提上去,把1和3變成2的子節(jié)點(diǎn)。

如果刪除節(jié)點(diǎn),會(huì)有相反的合并的操作。

注意這里是分裂和合并,跟AVL樹的左旋和右旋是不一樣的。

我們繼續(xù)插入4和5,B Tree又會(huì)出現(xiàn)分裂和合并的操作。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
從這個(gè)里面我們也能看到,在更新索引的時(shí)候會(huì)有大量的索引的結(jié)構(gòu)的調(diào)整,所以解釋了為什么我們不要在頻繁更新的列上建索引,或者為什么不要更新主鍵。

節(jié)點(diǎn)和分裂和合并,其實(shí)就是InnoDB頁的分裂和合并。

如果索引鍵值有序,寫滿一頁接著開辟一個(gè)新的頁:

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
如果索引鍵值無序,存儲(chǔ)過程造成大量磁盤碎片,帶來頻繁的page分裂和合并:

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

5、B+樹(加強(qiáng)版多路平衡查找樹)

算法-B-樹、B樹、B+樹詳解

B Tree的效率已經(jīng)很高了,為什么MySQL還要對(duì)B Tree進(jìn)行改良,最終使用了B+Tree呢?

總體上來說,這個(gè)B樹的改良版本解決的問題比B Tree更全面。我們來看一下InnoDB里面的B+樹的存儲(chǔ)結(jié)構(gòu):

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
MySQL中的B+Tree有幾個(gè)特點(diǎn):
1、它的關(guān)鍵字的數(shù)量是跟路數(shù)相等的;

2、B+Tree的根節(jié)點(diǎn)和枝節(jié)點(diǎn)中都不會(huì)存儲(chǔ)數(shù)據(jù),只有葉子結(jié)點(diǎn)才存儲(chǔ)數(shù)據(jù)
搜索到關(guān)鍵字不會(huì)直接返回,會(huì)到最后一層的葉子節(jié)點(diǎn)。比如我們搜索id = 28,雖然在第一層直接命中了,但是全部的數(shù)據(jù)在葉子節(jié)點(diǎn)上面,所以我還要繼續(xù)往下搜索,一直到葉子節(jié)點(diǎn)。

3、B+Tree的每個(gè)葉子節(jié)點(diǎn)增加了一個(gè)指向相鄰葉子節(jié)點(diǎn)的指針,它的最后一個(gè)數(shù)據(jù)會(huì)指向下一個(gè)葉子節(jié)點(diǎn)的第一個(gè)數(shù)據(jù),形成了一個(gè)有序鏈表的結(jié)構(gòu)。

(1)B+Tree搜索過程

1、比如我們要查找28,在根節(jié)點(diǎn)就找到了鍵值,但是因?yàn)樗皇侨~子結(jié)點(diǎn),所以會(huì)繼續(xù)往下搜尋,28是[28,66)的左閉右開的區(qū)間的臨界值,所以會(huì)走中間的子節(jié)點(diǎn),然后繼續(xù)搜索,它又是[28,34)的左閉右開區(qū)間的臨界值,所以會(huì)走左邊的子節(jié)點(diǎn),最后在葉子節(jié)點(diǎn)上找到了需要的數(shù)據(jù)。

2、第二個(gè),如果是范圍查詢,比如要查詢從22到60的數(shù)據(jù),當(dāng)找到22之后,只需要順著節(jié)點(diǎn)和指針順序遍歷就可以一次性訪問到所有的數(shù)據(jù)節(jié)點(diǎn),這樣就極大地提高了區(qū)間查詢效率(不需要返回上層父節(jié)點(diǎn)重復(fù)遍歷查找)。

(2)B+Tree帶來的優(yōu)勢(shì)

1、它是B Tree的變種,B Tree能解決的問題,它都能解決。B Tree解決的兩大問題,就是每個(gè)節(jié)點(diǎn)存儲(chǔ)更多的關(guān)鍵字、路數(shù)更多。
2、掃庫、掃表能力更強(qiáng)(如果我們要對(duì)表進(jìn)行全表掃描,只需要遍歷葉子節(jié)點(diǎn)就可以了,不需要遍歷整棵B+Tree拿到所有的數(shù)據(jù))。
3、B+Tree的磁盤讀寫能力相對(duì)于B Tree來說更強(qiáng)(根節(jié)點(diǎn)和枝節(jié)點(diǎn)不保存數(shù)據(jù),所以一個(gè)節(jié)點(diǎn)可以保存更多的關(guān)鍵字,一次磁盤加載的關(guān)鍵字更多)。
4、排序能力更強(qiáng)(因?yàn)槿~子節(jié)點(diǎn)上有下一個(gè)數(shù)據(jù)區(qū)的指針,數(shù)據(jù)形成了鏈表)。
5、效率更加穩(wěn)定(B+Tree永遠(yuǎn)是在葉子結(jié)點(diǎn)拿數(shù)據(jù),所以IO次數(shù)是最穩(wěn)定的)。

舉個(gè)例子:假設(shè)一條記是16bytes,一個(gè)葉子結(jié)點(diǎn)(一頁)可以存儲(chǔ)10條記錄。非葉子結(jié)點(diǎn)可以存儲(chǔ)多少個(gè)指針?
假設(shè)索引字段+指針大小為16字節(jié)。非葉子結(jié)點(diǎn)(一頁)可以存儲(chǔ)1000個(gè)這樣的單元(鍵值+指針),代表有1000個(gè)指針。
樹深度為2的時(shí)候,有10002個(gè)葉子節(jié)點(diǎn),可以存儲(chǔ)的數(shù)據(jù)位1000W(千萬級(jí)別)。

MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
在查找數(shù)據(jù)時(shí),一次頁的查找代表一次IO,也就是說,一張千萬級(jí)別的表,查詢數(shù)據(jù)最多需要訪問3次磁盤。

樹的深度是怎么來的?根據(jù)你的鍵值類型和數(shù)據(jù)量計(jì)算出來的。字段值越大、數(shù)據(jù)量越大,深度越大。

所以在InnoDB中B+樹深度一般為1-3層,它就能滿足千萬級(jí)的數(shù)據(jù)存儲(chǔ)。

因?yàn)锽 Tree和B+Tree的特性,它們廣泛地用在文件系統(tǒng)和數(shù)據(jù)庫中,例如windows的HPFS文件系統(tǒng),Oracle、MySQL、SQLServer數(shù)據(jù)庫。

6、為什么不用紅黑樹?

紅黑樹也是BST樹,但是不是嚴(yán)格平衡的,通過變色和旋轉(zhuǎn)來保持平衡。

必須滿足5個(gè)約束:
1、節(jié)點(diǎn)分為紅色或者黑色;2、根節(jié)點(diǎn)必須是黑色的;3、葉子節(jié)點(diǎn)都是黑色的NULL節(jié)點(diǎn);4、紅色節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)都是黑色(不允許兩個(gè)相鄰的紅色節(jié)點(diǎn));5、從任意節(jié)點(diǎn)觸發(fā),到其每個(gè)葉子節(jié)點(diǎn)的路徑中包含相同數(shù)量的黑色節(jié)點(diǎn)。

插入60、56、68、45、64、58、72、43、49
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
基于以上規(guī)則,可以推導(dǎo)出:從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的最長(zhǎng)路徑(紅黑相間的路徑)不大于最短路徑(全部是黑色節(jié)點(diǎn))的2倍。

為什么不用紅黑樹?1、只有兩路;2、不夠平衡。

紅黑樹一般只放在內(nèi)存里面用。例如Java的TreeMap,它可以用來實(shí)現(xiàn)一致性哈希。

6、hash索引

算法-hash散列表查找詳解

在navicat工具中,創(chuàng)建索引,索引方式還有一種是HASH索引,以KV的形式檢索數(shù)據(jù),也就是說,它會(huì)根據(jù)索引字段生成哈希碼和指針,指針指向數(shù)據(jù)。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

(1)哈希索引的特點(diǎn)

1、它的事件復(fù)雜度是O(1),查詢速度比較快。因?yàn)楣K饕锩娴臄?shù)據(jù)不是按順序存儲(chǔ)的,所以不能用于排序。
2、我們?cè)诓樵償?shù)據(jù)的時(shí)候要根據(jù)鍵值計(jì)算哈希碼,所以它只能支持等值查詢(= IN),不支持范圍查詢(> < >= <= between and)。
3、如果字段重復(fù)值很多的時(shí)候,會(huì)出現(xiàn)大量的哈希沖突(采用拉鏈法解決),效率會(huì)降低。

(2)注意

在InnoDB中,不能顯式地創(chuàng)建一個(gè)哈希索引(所謂的支持哈希索引指的是AHI,自適應(yīng)哈希,它是InnoDB自動(dòng)為buffer pool中的熱點(diǎn)頁創(chuàng)建的索引)。

memory存儲(chǔ)引擎可以使用Hash索引。

三、B+Tree的落地實(shí)現(xiàn)

1、認(rèn)識(shí)MySQL數(shù)據(jù)存儲(chǔ)文件

首先,MySQL的數(shù)據(jù)都是文件的形式存放在磁盤中的,我們可以找到這個(gè)數(shù)據(jù)目錄的地址。在MySQL中有這么一個(gè)參數(shù),我們來看一下:

show variables like 'datadir';

每個(gè)數(shù)據(jù)庫有一個(gè)目錄,我們新建了一個(gè)叫做test的數(shù)據(jù)庫,那么這里就有一個(gè)test的文件夾。

數(shù)據(jù)庫里面的幾張表,進(jìn)入test目錄之后,發(fā)現(xiàn)這里面有一些跟我們創(chuàng)建的表名對(duì)應(yīng)的文件。

在這里我們能看到,每張InnoDB的表有兩個(gè)文件(.frm和.ibd),MyISAM的表有三個(gè)文件(.frm、.MYD、.MYI)。

有一個(gè)是相同的文件.frm。.frm是MySQL里面表結(jié)構(gòu)定義的文件,不管你建表的時(shí)候選用任何一個(gè)存儲(chǔ)引擎都會(huì)生成。

主要是其他兩個(gè)文件,實(shí)現(xiàn)了MySQL不同存儲(chǔ)引擎的索引。

2、MyISAM

在MyISAM里面,有另外兩個(gè)文件:

一個(gè)是.MYD文件,D代表Data,是MyISAM的數(shù)據(jù)文件,存放數(shù)據(jù)記錄,比如我們的user_myisam表的所有的表數(shù)據(jù)。

一個(gè)是.MYI文件,I代表Index,是MyISAM的索引文件,存放索引,比如我們?cè)趇d字段上面創(chuàng)建了一個(gè)主鍵索引,那么主鍵索引就是在這個(gè)索引文件里面。一個(gè)索引就會(huì)有一棵B+Tree,所有的B+Tree都在這個(gè)myi文件里面。

也就是說,在MyISAM里面,索引和數(shù)據(jù)是兩個(gè)獨(dú)立的文件。

(1)MyISAM索引機(jī)制

MyISAM的B+Tree里面,葉子節(jié)點(diǎn)存儲(chǔ)的事數(shù)據(jù)文件對(duì)應(yīng)的磁盤地址。所以從索引文件.MYI中找到鍵值后,會(huì)到數(shù)據(jù)文件.MYD中獲取相應(yīng)的數(shù)據(jù)記錄。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle
除了主鍵索引,在MyISAM中,其他索引也在這個(gè).MYI文件里面。

-- name字段創(chuàng)建索引
ALTER TABLE user_innodb DROP INDEX idx_user_name;
ALTER TABLE user_innodb ADD INDEX idx_user_name (name);

非主鍵索引跟主鍵索引存儲(chǔ)和檢索數(shù)據(jù)的方式是沒有任何區(qū)別的,一樣是在索引文件里面找到磁盤地址,然后到數(shù)據(jù)文件里面獲取數(shù)據(jù)。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

3、InnoDB

與MyISAM不同,在InnoDB的某個(gè)索引的葉子節(jié)點(diǎn)上,它直接存儲(chǔ)了我們的數(shù)據(jù)。
所以,為什么說在InnoDB中索引即數(shù)據(jù),數(shù)據(jù)即索引,就是這個(gè)原因。

但是會(huì)有一個(gè)問題,一張InnoDB的表可能有很多個(gè)索引,數(shù)據(jù)肯定是只有一份的,那數(shù)據(jù)在哪個(gè)索引的葉子節(jié)點(diǎn)上呢?
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

(1)聚集索引(聚簇索引)

InnoDB引入了聚集索引(聚簇索引)的概念。索引鍵值的邏輯順序跟表數(shù)據(jù)行的物理存儲(chǔ)順序是一致的。

InnoDB組織數(shù)據(jù)的方式就是(聚集)索引組織表(clustered index organize table)。如果說一張表創(chuàng)建了主鍵索引,那么這個(gè)主鍵索引就是聚集索引,決定數(shù)據(jù)行的物理存儲(chǔ)順序。

(比如字典的目錄是按拼音排序的,內(nèi)容也是按拼音排序的,按拼音排序的這種目錄就叫聚集索引)

那么問題來了,主鍵索引之外的索引,會(huì)不會(huì)也把完整記錄在葉子節(jié)點(diǎn)放一份呢?答案是并不會(huì),因?yàn)檫@會(huì)帶來額外的存儲(chǔ)空間浪費(fèi)和計(jì)算消耗。

它們的葉子結(jié)點(diǎn)上沒有數(shù)據(jù)怎么檢索完整數(shù)據(jù)?比如我們?cè)趎ame字段上面建的普通索引。
MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式,mysql,mysql,b樹,oracle

(2)二級(jí)索引

InnoDB中,主鍵索引和輔助索引是有一個(gè)主次之分的。如果有主鍵索引,那么主鍵索引就是聚集索引。其他的索引統(tǒng)一叫做“二級(jí)索引”(secondary index)。

二級(jí)索引存儲(chǔ)的是二級(jí)索引的鍵值,例如在name上建立索引,節(jié)點(diǎn)上存的是name的值,qingshan tom等等(很明顯,它的鍵值邏輯順序跟物理行的順序不一致)。

而二級(jí)索引的葉子節(jié)點(diǎn)存的是這條記錄對(duì)應(yīng)的主鍵的值。比如qingshan id = 1,jack id = 4等等。

所以,二級(jí)索引檢索數(shù)據(jù)的流程是這樣的:
當(dāng)我們用name索引查詢一條記錄,它會(huì)在二級(jí)索引的葉子節(jié)點(diǎn)找到name=zhangsan,拿到主鍵,也就是id=1,然后再到主鍵索引的葉子節(jié)點(diǎn)拿到數(shù)據(jù)。

為什么不存地址而存鍵值呢?因?yàn)榈刂窌?huì)發(fā)生變化。

從這個(gè)角度來說,因?yàn)橹麈I索引比二級(jí)索引少掃描了一棵B+Tree(避免了回表),它的速度相對(duì)會(huì)快一些。

(3)一個(gè)表沒有主鍵

一張表沒有主鍵怎么辦?完整的記錄放在哪個(gè)索引的葉子節(jié)點(diǎn)?數(shù)據(jù)放在那里?
1、如果我們定義了主鍵(PRIMARY KEY),那么InnoDB會(huì)選擇主鍵作為聚集索引。
2、如果沒有顯式定義主鍵,則InnoDB會(huì)選擇第一個(gè)不包含有NULL值的唯一索引作為主鍵索引。
3、如果也沒有這樣的唯一索引,則InnoDB會(huì)選擇內(nèi)置6字節(jié)長(zhǎng)的ROWID作為隱藏的聚集索引,它會(huì)隨著記錄的寫入而主鍵遞增。文章來源地址http://www.zghlxwxcb.cn/news/detail-566480.html

select _rowid name from t;

到了這里,關(guān)于MySQL為什么要使用B+樹做索引?MySQL索引存儲(chǔ)模型推演,B+樹在MySQL的落地形式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • MySQL為什么選擇B+樹創(chuàng)建索引

    MySQL為什么選擇B+樹創(chuàng)建索引

    將磁盤中存儲(chǔ)的所有數(shù)據(jù)記錄依次加載,與給定條件對(duì)比,直到找到目標(biāo)記錄; 類比數(shù)組結(jié)構(gòu)的線性查找,效率較低; 結(jié)合數(shù)組和鏈表結(jié)構(gòu)(或者樹結(jié)構(gòu))存儲(chǔ)數(shù)據(jù); 通過哈希函數(shù)(散列函數(shù))計(jì)算哈希地址,相同輸入在固定函數(shù)下輸出保持不變; 哈希結(jié)構(gòu)會(huì)發(fā)生哈希沖突

    2024年02月13日
    瀏覽(18)
  • mysql的主鍵索引為什么不能null

    這是一個(gè)非常奇怪且有趣的問題??梢酝ㄟ^官方文檔進(jìn)行解讀 https://dev.mysql.com/doc/refman/5.7/en/glossary.html A special value in SQL, indicating the absence of data. Any arithmetic operation or equality test involving a NULL value, in turn produces a NULL result. (Thus it is similar to the IEEE floating-point concept of NaN, “not

    2024年02月14日
    瀏覽(25)
  • MySQL為什么采用B+樹作為索引底層數(shù)據(jù)結(jié)構(gòu)?

    MySQL為什么采用B+樹作為索引底層數(shù)據(jù)結(jié)構(gòu)?

    ????????索引就像一本書的目錄,通過索引可以快速找到我們想要找的內(nèi)容。那么什么樣的數(shù)據(jù)結(jié)構(gòu)可以用來實(shí)現(xiàn)索引呢?我們可能會(huì)想到:二叉查找樹,平衡搜索樹,或者是B樹等等一系列的數(shù)據(jù)結(jié)構(gòu),那么為什么MySQL最終選擇了B+樹作為索引的數(shù)據(jù)結(jié)構(gòu)呢? ? ? ? ? 要想

    2024年02月16日
    瀏覽(23)
  • MSQL系列(十二) Mysql實(shí)戰(zhàn)-為什么索引要建立在被驅(qū)動(dòng)表上

    MSQL系列(十二) Mysql實(shí)戰(zhàn)-為什么索引要建立在被驅(qū)動(dòng)表上

    Mysql實(shí)戰(zhàn)-為什么索引要建立在被驅(qū)動(dòng)表上 前面我們講解了B+Tree的索引結(jié)構(gòu),也詳細(xì)講解下 left Join的底層驅(qū)動(dòng)表 選擇原理,那么今天我們來看看到底如何用以及如何建立索引和索引優(yōu)化 開始之前我們先提一個(gè)問題, 為什么索引要建立在被驅(qū)動(dòng)表上 ? 1.建表及測(cè)試數(shù)據(jù) 我們先

    2024年02月08日
    瀏覽(43)
  • MySQL索引為什么選擇B+樹,而不是二叉樹、紅黑樹、B樹?

    MySQL索引為什么選擇B+樹,而不是二叉樹、紅黑樹、B樹?

    二叉樹是一種二分查找樹,有很好的查找性能,相當(dāng)于二分查找。 二叉樹的非葉子節(jié)值大于左邊子節(jié)點(diǎn)、小于右邊子節(jié)點(diǎn)。 原因: 但是當(dāng)N比較大的時(shí)候,樹的深度比較高。數(shù)據(jù)查詢的時(shí)間主要依賴于磁盤IO的次數(shù),二叉樹深度越大,查找的次數(shù)越多,性能越差。 最壞的情況

    2024年04月25日
    瀏覽(29)
  • 【Elasticsearch專欄 02】深入探索:Elasticsearch為什么使用倒排索引而不是正排索引

    Elasticsearch選擇使用倒排索引而不是正排索引,主要是基于倒排索引在處理全文搜索和大規(guī)模數(shù)據(jù)集時(shí)的優(yōu)勢(shì)。下面將詳細(xì)解釋為什么Elasticsearch更傾向于使用倒排索引,并提供一些簡(jiǎn)化的代碼片段來說明這兩種索引結(jié)構(gòu)的基本差異。 正排索引是一種將文檔映射到其包含的單詞

    2024年02月22日
    瀏覽(30)
  • 存儲(chǔ)過程為什么使用DELIMITER $$,存儲(chǔ)過程的詳細(xì)運(yùn)用解釋

    這是正確的存儲(chǔ)過程寫法,可以成功執(zhí)行,相比較上圖的報(bào)錯(cuò),增加了DELIMITER,簡(jiǎn)單解釋下這個(gè)命令的用途,在MySQL中每行命令都是用“;”結(jié)尾,回車后自動(dòng)執(zhí)行,在存儲(chǔ)過程中“;”往往不代表指令結(jié)束,馬上運(yùn)行,而DELIMITER原本就是“;”的意思,因此用這個(gè)命令轉(zhuǎn)換一

    2024年01月25日
    瀏覽(21)
  • 為什么 Golang Fasthttp 選擇使用 slice 而非 map 存儲(chǔ)請(qǐng)求數(shù)據(jù)

    為什么 Golang Fasthttp 選擇使用 slice 而非 map 存儲(chǔ)請(qǐng)求數(shù)據(jù)

    Fasthttp 是一個(gè)高性能的 Golang HTTP 框架,它在設(shè)計(jì)上做了許多優(yōu)化以提高性能。其中一個(gè)顯著的設(shè)計(jì)選擇是使用 slice 而非 map 來存儲(chǔ)數(shù)據(jù),尤其是在處理 HTTP headers 時(shí)。 為什么呢? 本文將從簡(jiǎn)單到復(fù)雜,逐步剖析為什么 Fasthttp 選擇使用 slice 而非 map,并通過代碼示例解釋這一

    2024年01月22日
    瀏覽(21)
  • MySQL為什么不推薦使用in

    有的時(shí)候博客內(nèi)容會(huì)有變動(dòng),首發(fā)博客是最新的,其他博客地址可能會(huì)未同步,認(rèn)準(zhǔn) https://blog.zysicyj.top 首發(fā)博客地址 系列文章地址 當(dāng)使用IN語句時(shí),MySQL可能會(huì)遇到以下問題: 索引問題:MySQL使用索引來加速查詢,但在使用IN語句時(shí),MySQL可能無法有效地使用索引。這是因?yàn)?/p>

    2024年02月09日
    瀏覽(25)
  • 為什么hive表不經(jīng)常用索引

    Hive 表不經(jīng)常使用索引的主要原因是由于其設(shè)計(jì)初衷和使用場(chǎng)景的特點(diǎn)。下面是一些可能的解釋: Hive 主要用于處理大規(guī)模數(shù)據(jù)集的批量分析任務(wù),而不是對(duì)單個(gè)記錄的實(shí)時(shí)查詢。對(duì)于批處理任務(wù),全表掃描通常是更為高效的方式,因?yàn)樗饕枰S護(hù)額外的數(shù)據(jù)結(jié)構(gòu)并帶來一

    2024年02月16日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包