搞定面試官 - 可以介紹一下 MySQL InnoDB 引擎的索引模型嘛唯绍?

大家好,我是啊粥枝誊。

接下來的幾天我們會開啟一個全新的系列文章况芒,那就是搞定面試官系列,我會把常見的面試知識通過這個專欄寫出來叶撒,比如我們常見的 Java绝骚、MySQL、Redis祠够、MQ 以及其他的一些技術(shù)框架压汪。

現(xiàn)在最先開啟的是 MySQL 系列,今天先來分享我們最常見的一個面試問題古瓤,那就是關(guān)于 MySQL 的索引止剖。

相信很多人在面試中會遇到關(guān)于 MySQL 索引的相關(guān)知識腺阳,從 MySQL 的架構(gòu)到索引模型,然后再到表設(shè)計(jì)穿香,SQL 優(yōu)化等等亭引。

首先,我們來看下索引是什么皮获?

索引概述

索引是一種幫助 MySQL 高效獲取數(shù)據(jù)的有序數(shù)據(jù)結(jié)構(gòu)焙蚓。

它的出現(xiàn)就是為了提高數(shù)據(jù)的查詢效率,就像書的目錄一樣洒宝。如果一本書沒有目錄购公,那我們就必須一頁一頁的去找我們自己想要的東西。

但是一旦有了目錄待德,那我們就可以快速的通過目錄了解書的全貌君丁,然后再根據(jù)具體的頁碼找到我們自己想要的東西。

MySQL 的索引就是類似的作用将宪,幫助我們快速且高效的獲取數(shù)據(jù)绘闷。

索引的常見模型

索引的實(shí)現(xiàn)有不同的方式,本質(zhì)上可以提高查詢效率的數(shù)據(jù)結(jié)構(gòu)有很多種较坛,這里先介紹三種比較常見的數(shù)據(jù)結(jié)構(gòu):

  • 哈希表

  • 有序數(shù)組

  • 樹形結(jié)構(gòu)

哈希表

以鍵值(key-value)形式存儲數(shù)據(jù)的結(jié)構(gòu)印蔗。哈希的方式非常簡單,是用一個哈希函數(shù)把 key 換算成一個確定的位置丑勤,然后把 value 放在數(shù)組的這個位置华嘹。

因?yàn)楣K惴ǖ脑颍鄠€ key 可能會存在 Hash 沖突法竞,這個時候一般會使用拉鏈法來解決沖突耙厚,也就是相同 Hash 值的拉出一個鏈表。

哈希表這種結(jié)果用來做等值查詢速度非巢戆裕快薛躬,但是因?yàn)樗菬o序的,如果是用來做區(qū)間查詢的話呆细,會非常慢型宝。

比如,我們有一張用戶的姓名和身份照號的表絮爷,如下是使用哈希表的方式存儲:

image.png

有序數(shù)組

以上數(shù)據(jù)如果使用有序數(shù)組來存儲的話趴酣,他的結(jié)構(gòu)是:

[圖片上傳失敗...(image-aaf42e-1660361093143)]

有序數(shù)組可以使用二分法很快進(jìn)行數(shù)據(jù)檢索,時間復(fù)雜度是 O(log(N))坑夯。但是更新數(shù)據(jù)會比較麻煩岖寞,因?yàn)橐S持順序,所以每次數(shù)據(jù)插入需要移動的元素太多了渊涝,成本太高慎璧。

所以床嫌,有序數(shù)組只適用于靜態(tài)存儲引擎。

搜索樹

同理胸私,使用二叉樹來存儲的話厌处,結(jié)構(gòu)如下

image.png

二叉搜索樹的特點(diǎn)是:父節(jié)點(diǎn)左子樹所有結(jié)點(diǎn)的值小于父節(jié)點(diǎn)的值,右子樹所有結(jié)點(diǎn)的值大于父節(jié)點(diǎn)的值岁疼。這樣如果你要查 id_card_03 的話阔涉,按照圖中的搜索順序就是按照 USERA -> USERC -> USERF -> USER_03 這個路徑得到。

這個時間復(fù)雜度是 O(log(N))捷绒。

當(dāng)然為了維持 O(log(N)) 的查詢復(fù)雜度瑰排,就需要保持這棵樹是平衡二叉樹。為了做這個保證暖侨,更新的時間復(fù)雜度也是 O(log(N))椭住。

二叉樹是搜索效率最高的,但是實(shí)際上大多數(shù)的數(shù)據(jù)庫存儲卻并不使用二叉樹字逗。其原因是京郑,索引不止存在內(nèi)存中,還要寫到磁盤上葫掉。

N 叉樹由于在讀寫上的性能優(yōu)點(diǎn)些举,以及適配磁盤的訪問模式,已經(jīng)被廣泛應(yīng)用在數(shù)據(jù)庫引擎中了俭厚。

但是户魏,二叉樹也是分很多種的,比如有 B-Tree挪挤、B+Tree 以及紅黑樹等等叼丑。

一般來說,一棵 100 萬節(jié)點(diǎn)的平衡二叉樹扛门,樹高 20幢码。一次查詢可能需要訪問 20 個數(shù)據(jù)塊。在機(jī)械硬盤時代尖飞,從磁盤隨機(jī)讀一個數(shù)據(jù)塊需要 10 ms 左右的尋址時間。也就是說店雅,對于一個 100 萬行的表政基,如果使用二叉樹來存儲,單獨(dú)訪問一個行可能需要 20 個 10 ms 的時間闹啦,這個查詢可真夠慢的沮明。

所以,我們需要找到另一種更加適合用來做 MySQL 索引引擎的數(shù)據(jù)結(jié)構(gòu)窍奋。

Innodb 的索引模型

InnoDB 使用了 B+ 樹作為索引結(jié)構(gòu)荐健,所有的元素都會出現(xiàn)在葉子節(jié)點(diǎn)上酱畅,同時,葉子節(jié)點(diǎn)之間會通過雙向鏈表連接江场。

InnoDB 使用 B+ Tree 使用索引結(jié)構(gòu)主要有以下原因:

  • 相比于二叉樹纺酸,B+ 數(shù)層級更少,搜索效率更高址否。

    • 以 InnoDB 的一個整數(shù)字段索引為例餐蔬,這個 N 差不多是 1200。這棵樹高是 4 的時候佑附,就可以存 1200 的 3 次方個值樊诺,這已經(jīng) 17 億了∫敉考慮到樹根的數(shù)據(jù)塊總是在內(nèi)存中的词爬,一個 10 億行的表上一個整數(shù)字段的索引,查找一個值最多只需要訪問 3 次磁盤权均。其實(shí)顿膨,樹的第二層也有很大概率在內(nèi)存中,那么訪問磁盤的平均次數(shù)就更少了螺句。
  • B 樹的葉子節(jié)點(diǎn)以及非葉子節(jié)點(diǎn)虽惭,都會保存數(shù)據(jù),這樣會導(dǎo)致一頁中存儲的鍵值減少蛇尚,指針跟著減少芽唇,要保存同樣多的數(shù)據(jù),只能增加樹的高度取劫,導(dǎo)致搜索性能降低匆笤。

在 InnoDB 中,表都是根據(jù)主鍵順序以索引的形式存放的谱邪,這種存儲方式的表稱為索引組織表炮捧。

每一個索引在 InnoDB 里面對應(yīng)一棵 B+ 樹。

假設(shè)表中 T1 ~ T5 的 (id,age) 值分別為 (1,10)惦银、(2,20)咆课、(3,30)、(5,50) 和 (6,60)扯俱,兩棵索引樹的示例示意圖如下书蚪。

主鍵索引樹
image.png
二級索引樹
image.png

從圖中不難看出,兩個索引輸?shù)娜~子結(jié)點(diǎn)內(nèi)容是不一樣的迅栅。根據(jù)葉子節(jié)點(diǎn)的內(nèi)容殊校,可以把索引類型分為主鍵索引和非主鍵索引。

主鍵索引的葉子節(jié)點(diǎn)存的是整行數(shù)據(jù)读存。而非主鍵索引的葉子結(jié)點(diǎn)存儲的是主鍵的值为流。

在 InnoDB 里呕屎,主鍵索引也被稱為聚簇索引(clustered index),非主鍵索引也被稱為二級索引(secondary index)敬察。

基于主鍵索引和普通索引的查詢有什么區(qū)別秀睛?

如果語句是 select * from test where id = 5,即主鍵查詢方式静汤,則只需要搜索 id 這棵 B+ 樹琅催;

如果語句是 select * from test where age = 50,即普通索引查詢方式虫给,則需要先搜索 age 索引樹藤抡,得到 id 的值為 5,再到 id 索引樹搜索一次抹估。

這個過程稱為回表缠黍,也就是說,基于非主鍵索引的查詢需要多掃描一棵索引樹药蜻。

因此瓷式,我們在應(yīng)用中應(yīng)該盡量使用主鍵查詢。

索引維護(hù)的開銷

B+ 樹為了維護(hù)索引有序性语泽,在插入新值的時候需要做必要的維護(hù)贸典。

以上面這個圖為例,如果插入新的行 id 值為 7踱卵,則只需要在 T5 的記錄后面插入一個新記錄廊驼。

如果新插入的 ID 值為 4,就相對麻煩了惋砂,需要在邏輯上挪動后面的數(shù)據(jù)妒挎,空出位置給 4,B+ 樹要做結(jié)構(gòu)變化西饵,維持平衡和節(jié)點(diǎn)順序酝掩。

而更糟的情況是,如果 T5 所在的數(shù)據(jù)頁已經(jīng)滿了眷柔,根據(jù) B+ 樹的算法期虾,這時候需要申請一個新的數(shù)據(jù)頁,然后挪動部分?jǐn)?shù)據(jù)過去驯嘱,這個過程稱為頁分裂彻消。

在這種情況下,性能自然會受影響宙拉。

除了影響性能外,頁分裂操作還會影響數(shù)據(jù)頁的利用率丙笋,因?yàn)樵痉旁谝粋€頁的數(shù)據(jù)谢澈,現(xiàn)在分到兩個頁中煌贴,整體空間利用率會降低大約 50%。

同理锥忿,有分裂就有合并牛郑。

當(dāng)相鄰兩個頁由于刪除了數(shù)據(jù),利用率很低之后敬鬓,會將數(shù)據(jù)頁做合并淹朋,合并的過程,可以認(rèn)為是分裂過程的逆過程钉答。將利用率低的頁數(shù)據(jù)進(jìn)行合并之后础芍,另一個數(shù)據(jù)葉會被標(biāo)記為可復(fù)用供后續(xù)數(shù)據(jù)利用,

所以我們?yōu)槭裁唇ㄗh使用自增主鍵数尿,因?yàn)?strong>自增主鍵的插入數(shù)據(jù)模式仑性,正好符合了我們前面提到的遞增插入的場景。

每次插入一條新記錄右蹦,都是追加操作诊杆,所以不涉及到挪動其他記錄,也不會觸發(fā)葉子節(jié)點(diǎn)的分裂何陆。反之晨汹,如果是使用業(yè)務(wù)邏輯的字段做主鍵,則往往沒法保證有序插入贷盲,這樣寫數(shù)據(jù)成本會相對較高淘这。

好了,我們做個簡單的總結(jié):

MySQL 選取了 B+ 樹作為它的索引模型來存儲數(shù)據(jù)晃洒,不但可以合理的利用磁盤特性慨灭,而且可以很方便的做范圍查詢,同時球及,因?yàn)?B+ 樹在非葉子節(jié)點(diǎn)不存儲數(shù)據(jù)氧骤,只在葉子節(jié)點(diǎn)存儲數(shù)據(jù),同等高度的 B+ 樹和 B 樹吃引,B + 樹可以存更多的數(shù)據(jù)筹陵,反之,同等的數(shù)據(jù)量镊尺,B+ 樹高度更低朦佩,假設(shè)每次節(jié)點(diǎn)搜索都是一次磁盤 IO 的話,那么庐氮,B+ 樹可以花更少的時間來獲取到所需要的數(shù)據(jù)语稠。

MySQL 的索引模型我們今天就先介紹到這里,文末留給大家一個問題,你有沒有遇到過仙畦,你明明執(zhí)行 delete 命令把表里的數(shù)據(jù)都刪除了输涕,但是表文件的大小卻沒有發(fā)生變化的情況?

如果有的話慨畸,歡迎留言我們一起討論莱坎,答案在下一篇文章中揭曉。

我是程序員啊粥寸士,關(guān)注我檐什,我們一起在技術(shù)海洋中向上生長。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弱卡,一起剝皮案震驚了整個濱河市乃正,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谐宙,老刑警劉巖烫葬,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凡蜻,居然都是意外死亡搭综,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門划栓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兑巾,“玉大人,你說我怎么就攤上這事忠荞〗瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵委煤,是天一觀的道長堂油。 經(jīng)常有香客問我,道長碧绞,這世上最難降的妖魔是什么府框? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮讥邻,結(jié)果婚禮上迫靖,老公的妹妹穿的比我還像新娘。我一直安慰自己兴使,他們只是感情好系宜,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著发魄,像睡著了一般盹牧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天汰寓,我揣著相機(jī)與錄音吆寨,去河邊找鬼。 笑死踩寇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的六水。 我是一名探鬼主播俺孙,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掷贾!你這毒婦竟也來了睛榄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤想帅,失蹤者是張志新(化名)和其女友劉穎场靴,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體港准,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旨剥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浅缸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轨帜。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衩椒,靈堂內(nèi)的尸體忽然破棺而出蚌父,到底是詐尸還是另有隱情,我是刑警寧澤毛萌,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布苟弛,位于F島的核電站,受9級特大地震影響阁将,放射性物質(zhì)發(fā)生泄漏膏秫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一冀痕、第九天 我趴在偏房一處隱蔽的房頂上張望荔睹。 院中可真熱鬧,春花似錦言蛇、人聲如沸僻他。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吨拗。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間劝篷,已是汗流浹背哨鸭。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娇妓,地道東北人像鸡。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像哈恰,于是被迫代替她去往敵國和親只估。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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