mysql索引底层图_MySQL索引底层数据结构
一、何為索引?
1、索引是幫助數(shù)據(jù)庫(kù)高效獲取數(shù)據(jù)的排好序的數(shù)據(jù)結(jié)構(gòu)。
2、索引存儲(chǔ)在文件中。
3、索引建多了會(huì)影響增刪改效率。(一張表最多允許建16個(gè)索引)
(下面這張圖為計(jì)算機(jī)組成原理內(nèi)容,每查詢一次索引節(jié)點(diǎn),都會(huì)進(jìn)行一次磁盤(pán)IO讀取,即要尋道和旋轉(zhuǎn))
二、MySQL索引結(jié)構(gòu)為什么是B+樹(shù)?
MySQL 建索引可使用的數(shù)據(jù)結(jié)構(gòu)有B+樹(shù)和Hash兩種,但是Hash用得很少, 優(yōu)點(diǎn)是可以快速定位到某一行,缺點(diǎn)是不能解決范圍查詢問(wèn)題。
對(duì)于如果不需要使用范圍查詢、只需要精準(zhǔn)查詢的場(chǎng)景,可以使用Hash索引方法,比如查電話號(hào)碼。
再說(shuō)說(shuō)主流的索引方法B+樹(shù),先說(shuō)下為什么不用別的樹(shù)結(jié)構(gòu),再說(shuō)為什么用B+樹(shù)。
1、為什么不用二叉樹(shù)?
如果碰到下面這種單邊增長(zhǎng)的極端情況,查找節(jié)點(diǎn)4和順序查找沒(méi)區(qū)別。(這種特殊情況的二叉樹(shù)等同于鏈表,時(shí)間復(fù)雜度為O(n))
2、為什么不用紅黑樹(shù)?
紅黑樹(shù)是一顆平衡二叉樹(shù),數(shù)據(jù)量大的時(shí)候,樹(shù)的深度也很深,如果樹(shù)的深度有20層,而查找的數(shù)據(jù)在葉子節(jié)點(diǎn),就要進(jìn)行20次IO操作,性能低。
3、為什么不用B樹(shù)?
B樹(shù)的特點(diǎn):
葉子節(jié)點(diǎn)具有相同的深度
葉子節(jié)點(diǎn)的指針為空
葉子節(jié)點(diǎn)中的數(shù)據(jù)key從左到右遞增排列
其實(shí)B樹(shù)就是在橫向做了文章,一個(gè)節(jié)點(diǎn)可以存儲(chǔ)更多數(shù)據(jù)(大節(jié)點(diǎn)包含很多小節(jié)點(diǎn)),這樣相對(duì)來(lái)說(shuō),深度就會(huì)變淺。
提問(wèn):橫向的節(jié)點(diǎn)怎么查,比如說(shuō)查找上圖中的節(jié)點(diǎn)77?
從磁盤(pán)中把大節(jié)點(diǎn)查找出來(lái),把這個(gè)大節(jié)點(diǎn)加載進(jìn)內(nèi)存中,節(jié)點(diǎn)77實(shí)際上是在內(nèi)存中查找的,在內(nèi)存中做的是隨機(jī)訪問(wèn),速度很快,跟磁盤(pán)的尋道和旋轉(zhuǎn)相比的話,基本可以忽略不計(jì)。
提問(wèn):為什么不可以讓B樹(shù)橫向的度無(wú)限增大,這樣不就深度為1,查找不就更快了?(度的含義:節(jié)點(diǎn)的數(shù)據(jù)存儲(chǔ)個(gè)數(shù))
本來(lái)是想通過(guò)一次IO操作把一個(gè)大節(jié)點(diǎn)加載進(jìn)內(nèi)存,如果一個(gè)大節(jié)點(diǎn)的數(shù)據(jù)量太大的話, 則內(nèi)存和硬盤(pán)一次交互沒(méi)辦法交換那么多數(shù)據(jù),假設(shè)一次只能交換1頁(yè)(4k)的數(shù)據(jù)(有上限,也有可能是幾十頁(yè),和計(jì)算機(jī)硬件有關(guān)),意味著CPU去硬盤(pán)上做一次IO操作只能取1頁(yè)的數(shù)據(jù),那么當(dāng)一個(gè)大節(jié)點(diǎn)的數(shù)據(jù)量太大時(shí),仍要進(jìn)行多次IO操作。因此,度是有上限的,MySQL會(huì)根據(jù)計(jì)算機(jī)硬件自動(dòng)進(jìn)行度的優(yōu)化,一個(gè)大節(jié)點(diǎn)通常為1頁(yè)空間。
4、為什么使用B+樹(shù)?(B+樹(shù)是B樹(shù)的變種,索引做了冗余,存了多份,但是沒(méi)關(guān)系,索引只占很小空間,比如下圖中的15節(jié)點(diǎn))
B+樹(shù)的特點(diǎn):
非葉子節(jié)點(diǎn)不存儲(chǔ)data,只存儲(chǔ)key,可以增大度(相比B樹(shù),B+樹(shù)的深度更淺)
葉子節(jié)點(diǎn)不存儲(chǔ)指針
順序訪問(wèn)指針,提高區(qū)間訪問(wèn)的性能(實(shí)際上是雙向指針)
提問(wèn):為什么說(shuō)B+樹(shù)可以增大度?
因?yàn)榉侨~子節(jié)點(diǎn)只存儲(chǔ)索引一個(gè)值,不存儲(chǔ)data(B樹(shù)會(huì)存儲(chǔ)data),而大節(jié)點(diǎn)大小是確定的,因此大節(jié)點(diǎn)就可以存儲(chǔ)更多的數(shù)據(jù),即度可以變得更大。這樣既保證度可以達(dá)到最大,又保證一個(gè)大節(jié)點(diǎn)通過(guò)一次IO操作可以加載進(jìn)內(nèi)存。(非葉子節(jié)點(diǎn)度更大,深度更淺,只有非葉子節(jié)點(diǎn)才影響查找次數(shù),葉子節(jié)點(diǎn)是最后一次查找,對(duì)總的查找次數(shù)是沒(méi)有影響的,因此把data全部移到了葉子節(jié)點(diǎn))
提問(wèn):為什么葉子節(jié)點(diǎn)之間還需要用指針?(一個(gè)大節(jié)點(diǎn)的尾節(jié)點(diǎn)和下一個(gè)大節(jié)點(diǎn)的頭節(jié)點(diǎn)之間的指針連接)
方便范圍查詢。比如查找上圖中key>18,如果沒(méi)有指針會(huì)非常麻煩,必須從頭開(kāi)始查找,如果有指針,則可以直接遍歷key>18的葉子節(jié)點(diǎn)(鏈表)。
B+樹(shù)索引的性能分析:
一般使用磁盤(pán)I/O次數(shù)評(píng)價(jià)索引結(jié)構(gòu)的優(yōu)劣
預(yù)讀:磁盤(pán)一般會(huì)順序向后讀取一定長(zhǎng)度的數(shù)據(jù)(頁(yè)的整數(shù)倍)放入內(nèi)存
局部性原理:當(dāng)一個(gè)數(shù)據(jù)被用到時(shí),其附近的數(shù)據(jù)也通常會(huì)立馬被使用
B+樹(shù)的大節(jié)點(diǎn)大小設(shè)為等于一個(gè)頁(yè),每次新建大節(jié)點(diǎn)直接申請(qǐng)一個(gè)頁(yè)的空間,這能保證一個(gè)大節(jié)點(diǎn)物理上也存儲(chǔ)在一個(gè)頁(yè)里,大節(jié)點(diǎn)載入只需一次IO操作
B+樹(shù)的度d一般會(huì)超過(guò)100,因此高度h非常小(一般為3~5之間)
三、MySQL底層是怎么用B+樹(shù)來(lái)存儲(chǔ)數(shù)據(jù)的?
MySQL有兩種常見(jiàn)的存儲(chǔ)引擎:InnoDB(默認(rèn))、MyISAM(用得少,在MySQL8.0中被廢棄掉了),存儲(chǔ)引擎范圍是表級(jí)別的。
1、MyISAM索引實(shí)現(xiàn)(非聚集)
索引文件和數(shù)據(jù)文件是分離的
索引結(jié)構(gòu)的葉子節(jié)點(diǎn)value存儲(chǔ)的是文件指針。
.frm是表結(jié)構(gòu)文件,.MYD是數(shù)據(jù)文件(MyISAM Data),.MYI是索引文件(MyISAM Index)。
MyISAM主鍵索引查找流程:先通過(guò).MYI文件找到對(duì)應(yīng)索引的文件指針,再根據(jù)文件指針去.MYD文件中定位對(duì)應(yīng)的那行數(shù)據(jù)。
MyISAM普通索引查找流程:和主鍵索引查找流程一致。
2、InnoDB索引實(shí)現(xiàn)(聚集)
數(shù)據(jù)文件本身就是索引文件
表數(shù)據(jù)文件本身就是按B+樹(shù)組織的一個(gè)索引結(jié)構(gòu)文件
聚集索引的葉子節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄
表必須有主鍵,且推薦使用整型的自增主鍵
普通索引結(jié)構(gòu)葉子節(jié)點(diǎn)存儲(chǔ)的是主鍵值
.frm是表結(jié)構(gòu)文件,.ibd是數(shù)據(jù)和索引文件(InnoDB Data)
InnoDB主鍵索引查找流程:通過(guò).ibd文件找到對(duì)應(yīng)的索引,索引的value即為那行對(duì)應(yīng)的完整數(shù)據(jù)。
InnoDB普通索引查找流程:通過(guò).ibd文件找到對(duì)應(yīng)的索引,索引的value即為那行對(duì)應(yīng)的主鍵的值,再根據(jù)主鍵值去主鍵索引樹(shù)中找到對(duì)應(yīng)的行數(shù)據(jù)。
提問(wèn):聚集索引和非聚集索引的區(qū)別?
聚集索引:表中那行數(shù)據(jù)的索引和數(shù)據(jù)都合并在一起了。
非聚集索引:表中那行數(shù)據(jù)的索引和數(shù)據(jù)是分開(kāi)存儲(chǔ)的。
提問(wèn):為什么InnoDB表必須有主鍵?
因?yàn)檎麄€(gè)數(shù)據(jù)文件本身就是按照B+樹(shù)組織的一個(gè)索引文件,所以必須要有主鍵(建InnoDB表時(shí)不指定主鍵,默認(rèn)會(huì)從表字段中選一列作為唯一主鍵,如果不存在這種字段,則后臺(tái)默認(rèn)生成一個(gè)長(zhǎng)整型主鍵字段,MyISAM可以沒(méi)有)。
提問(wèn):為什么推薦使用整型的自增主鍵?
提高查詢性能。如果是使用UUID作為主鍵,第一,UUID長(zhǎng)度很長(zhǎng),會(huì)浪費(fèi)存儲(chǔ)空間,第二,UUID是字符串類型,比較大小要查找ASCII碼表,查找速度沒(méi)有整型int查找速度快,第三,UUID是隨機(jī)生成無(wú)序的字符串,當(dāng)數(shù)據(jù)插入時(shí),有很大可能會(huì)導(dǎo)致節(jié)點(diǎn)位置移動(dòng),還可能造成很多其他節(jié)點(diǎn)位置移動(dòng),簡(jiǎn)單來(lái)說(shuō)就是位置打亂了。 如果使用整型的自增主鍵,新插入的數(shù)據(jù)都會(huì)連續(xù)的插入到磁盤(pán)的物理空間。
提問(wèn):為什么InnoDB普通索引結(jié)構(gòu)葉子節(jié)點(diǎn)存儲(chǔ)的是主鍵值?(一致性和節(jié)省存儲(chǔ)空間)
如果普通索引的value也存數(shù)據(jù),那么當(dāng)往有主鍵索引和普通索引的表中插入數(shù)據(jù)時(shí),索引結(jié)構(gòu)中key對(duì)應(yīng)的value要存儲(chǔ)兩份數(shù)據(jù),增加維護(hù)成本。
單值索引:只有一個(gè)索引,如(id),size=1
聯(lián)合索引:多個(gè)索引合起來(lái)作為一個(gè)聯(lián)合索引,如(id,name),size>1(單值索引是聯(lián)合索引size=1的特例)
提問(wèn):聯(lián)合索引的底層數(shù)據(jù)結(jié)構(gòu)長(zhǎng)什么樣?
(葉子節(jié)點(diǎn)key是聯(lián)合索引值,value是除聯(lián)合索引以外一行記錄其他字段的完整數(shù)據(jù))
先比較id,如果id相等,再比較name,如果name也相等,則再比較date。(索引最左前綴原理,后面索引優(yōu)化隨筆會(huì)講解)
總結(jié)
以上是生活随笔為你收集整理的mysql索引底层图_MySQL索引底层数据结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: zabbix-server-mysql安
- 下一篇: 6大主流开源SQL引擎总结,遥遥领先的是