深入理解?MySQL?索引底層原理
一步一步推導(dǎo)出 Mysql 索引的底層數(shù)據(jù)結(jié)構(gòu)。
Mysql 作為互聯(lián)網(wǎng)中非常熱門(mén)的數(shù)據(jù)庫(kù),其底層的存儲(chǔ)引擎和數(shù)據(jù)檢索引擎的設(shè)計(jì)非常重要,尤其是 Mysql 數(shù)據(jù)的存儲(chǔ)形式以及索引的設(shè)計(jì),決定了 Mysql 整體的數(shù)據(jù)檢索性能。
我們知道,索引的作用是做數(shù)據(jù)的快速檢索,而快速檢索的實(shí)現(xiàn)的本質(zhì)是數(shù)據(jù)結(jié)構(gòu)。通過(guò)不同數(shù)據(jù)結(jié)構(gòu)的選擇,實(shí)現(xiàn)各種數(shù)據(jù)快速檢索。在數(shù)據(jù)庫(kù)中,高效的查找算法是非常重要的,因?yàn)閿?shù)據(jù)庫(kù)中存儲(chǔ)了大量數(shù)據(jù),一個(gè)高效的索引能節(jié)省巨大的時(shí)間。比如下面這個(gè)數(shù)據(jù)表,如果 Mysql 沒(méi)有實(shí)現(xiàn)索引算法,那么查找 id=7 這個(gè)數(shù)據(jù),那么只能采取暴力順序遍歷查找,找到 id=7 這個(gè)數(shù)據(jù)需要比較 7 次,如果這個(gè)表存儲(chǔ)的是 1000W 個(gè)數(shù)據(jù),查找 id=1000W 這個(gè)數(shù)據(jù)那就要比較 1000W 次,這種速度是不能接受的。
Mysql 索引底層數(shù)據(jù)結(jié)構(gòu)選型
哈希表(Hash)
哈希表是做數(shù)據(jù)快速檢索的有效利器。
哈希算法:也叫散列算法,就是把任意值(key)通過(guò)哈希函數(shù)變換為固定長(zhǎng)度的 key 地址,通過(guò)這個(gè)地址進(jìn)行具體數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。
考慮這個(gè)數(shù)據(jù)庫(kù)表 user,表中一共有 7 個(gè)數(shù)據(jù),我們需要檢索 id=7 的數(shù)據(jù),SQL 語(yǔ)法是:
select * from user where id = 7;
哈希算法首先計(jì)算存儲(chǔ) id=7 的數(shù)據(jù)的物理地址 addr=hash(7)=4231,而 4231 映射的物理地址是 0x77,0x77 就是 id=7 存儲(chǔ)的額數(shù)據(jù)的物理地址,通過(guò)該獨(dú)立地址可以找到對(duì)應(yīng) user_name='g'這個(gè)數(shù)據(jù)。這就是哈希算法快速檢索數(shù)據(jù)的計(jì)算過(guò)程。
但是哈希算法有個(gè)數(shù)據(jù)碰撞的問(wèn)題,也就是哈希函數(shù)可能對(duì)不同的 key 會(huì)計(jì)算出同一個(gè)結(jié)果,比如 hash(7)可能跟 hash(199)計(jì)算出來(lái)的結(jié)果一樣,也就是不同的 key 映射到同一個(gè)結(jié)果了,這就是碰撞問(wèn)題。解決碰撞問(wèn)題的一個(gè)常見(jiàn)處理方式就是鏈地址法,即用鏈表把碰撞的數(shù)據(jù)接連起來(lái)。計(jì)算哈希值之后,還需要檢查該哈希值是否存在碰撞數(shù)據(jù)鏈表,有則一直遍歷到鏈表尾,直達(dá)找到真正的 key 對(duì)應(yīng)的數(shù)據(jù)為止。
從算法時(shí)間復(fù)雜度分析來(lái)看,哈希算法時(shí)間復(fù)雜度為 O(1),檢索速度非???。比如查找 id=7 的數(shù)據(jù),哈希索引只需要計(jì)算一次就可以獲取到對(duì)應(yīng)的數(shù)據(jù),檢索速度非???。但是 Mysql 并沒(méi)有采取哈希作為其底層算法,這是為什么呢?
因?yàn)榭紤]到數(shù)據(jù)檢索有一個(gè)常用手段就是范圍查找,比如以下這個(gè) SQL 語(yǔ)句:
select \* fromuserwhereid \>3;
針對(duì)以上這個(gè)語(yǔ)句,我們希望做的是找出 id>3 的數(shù)據(jù),這是很典型的范圍查找。如果使用哈希算法實(shí)現(xiàn)的索引,范圍查找怎么做呢?一個(gè)簡(jiǎn)單的思路就是一次把所有數(shù)據(jù)找出來(lái)加載到內(nèi)存,然后再在內(nèi)存里篩選篩選目標(biāo)范圍內(nèi)的數(shù)據(jù)。但是這個(gè)范圍查找的方法也太笨重了,沒(méi)有一點(diǎn)效率而言。
所以,使用哈希算法實(shí)現(xiàn)的索引雖然可以做到快速檢索數(shù)據(jù),但是沒(méi)辦法做數(shù)據(jù)高效范圍查找,因此哈希索引是不適合作為 Mysql 的底層索引的數(shù)據(jù)結(jié)構(gòu)。
二叉查找樹(shù)(BST)
二叉查找樹(shù)是一種支持?jǐn)?shù)據(jù)快速查找的數(shù)據(jù)結(jié)構(gòu),如圖下所示:
二叉查找樹(shù)的時(shí)間復(fù)雜度是 O(lgn),比如針對(duì)上面這個(gè)二叉樹(shù)結(jié)構(gòu),我們需要計(jì)算比較 3 次就可以檢索到 id=7 的數(shù)據(jù),相對(duì)于直接遍歷查詢(xún)省了一半的時(shí)間,從檢索效率上看來(lái)是能做到高速檢索的。此外二叉樹(shù)的結(jié)構(gòu)能不能解決哈希索引不能提供的范圍查找功能呢?
答案是可以的。觀(guān)察上面的圖,二叉樹(shù)的葉子節(jié)點(diǎn)都是按序排列的,從左到右依次升序排列,如果我們需要找 id>5 的數(shù)據(jù),那我們?nèi)〕龉?jié)點(diǎn)為 6 的節(jié)點(diǎn)以及其右子樹(shù)就可以了,范圍查找也算是比較容易實(shí)現(xiàn)。
但是普通的二叉查找樹(shù)有個(gè)致命缺點(diǎn):極端情況下會(huì)退化為線(xiàn)性鏈表,二分查找也會(huì)退化為遍歷查找,時(shí)間復(fù)雜退化為 O(N),檢索性能急劇下降。比如以下這個(gè)情況,二叉樹(shù)已經(jīng)極度不平衡了,已經(jīng)退化為鏈表了,檢索速度大大降低。此時(shí)檢索 id=7 的數(shù)據(jù)的所需要計(jì)算的次數(shù)已經(jīng)變?yōu)?7 了。
在數(shù)據(jù)庫(kù)中,數(shù)據(jù)的自增是一個(gè)很常見(jiàn)的形式,比如一個(gè)表的主鍵是 id,而主鍵一般默認(rèn)都是自增的,如果采取二叉樹(shù)這種數(shù)據(jù)結(jié)構(gòu)作為索引,那上面介紹到的不平衡狀態(tài)導(dǎo)致的線(xiàn)性查找的問(wèn)題必然出現(xiàn)。因此,簡(jiǎn)單的二叉查找樹(shù)存在不平衡導(dǎo)致的檢索性能降低的問(wèn)題,是不能直接用于實(shí)現(xiàn) Mysql 底層索引的。
AVL 樹(shù)和紅黑樹(shù)
二叉查找樹(shù)存在不平衡問(wèn)題,因此學(xué)者提出通過(guò)樹(shù)節(jié)點(diǎn)的自動(dòng)旋轉(zhuǎn)和調(diào)整,讓二叉樹(shù)始終保持基本平衡的狀態(tài),就能保持二叉查找樹(shù)的最佳查找性能了?;谶@種思路的自調(diào)整平衡狀態(tài)的二叉樹(shù)有 AVL 樹(shù)和紅黑樹(shù)。
首先簡(jiǎn)單介紹紅黑樹(shù),這是一顆會(huì)自動(dòng)調(diào)整樹(shù)形態(tài)的樹(shù)結(jié)構(gòu),比如當(dāng)二叉樹(shù)處于一個(gè)不平衡狀態(tài)時(shí),紅黑樹(shù)就會(huì)自動(dòng)左旋右旋節(jié)點(diǎn)以及節(jié)點(diǎn)變色,調(diào)整樹(shù)的形態(tài),使其保持基本的平衡狀態(tài)(時(shí)間復(fù)雜度為 O(logn)),也就保證了查找效率不會(huì)明顯減低。比如從 1 到 7 升序插入數(shù)據(jù)節(jié)點(diǎn),如果是普通的二叉查找樹(shù)則會(huì)退化成鏈表,但是紅黑樹(shù)則會(huì)不斷調(diào)整樹(shù)的形態(tài),使其保持基本平衡狀態(tài),如下圖所示。下面這個(gè)紅黑樹(shù)下查找 id=7 的所要比較的節(jié)點(diǎn)數(shù)為 4,依然保持二叉樹(shù)不錯(cuò)的查找效率。
紅黑樹(shù)擁有不錯(cuò)的平均查找效率,也不存在極端的 O(n)情況,那紅黑樹(shù)作為 Mysql 底層索引實(shí)現(xiàn)是否可以呢?其實(shí)紅黑樹(shù)也存在一些問(wèn)題,觀(guān)察下面這個(gè)例子。
紅黑樹(shù)順序插入 1~7 個(gè)節(jié)點(diǎn),查找 id=7 時(shí)需要計(jì)算的節(jié)點(diǎn)數(shù)為 4。
紅黑樹(shù)順序插入 1~16 個(gè)節(jié)點(diǎn),查找 id=16 需要比較的節(jié)點(diǎn)數(shù)為 6 次。觀(guān)察一下這個(gè)樹(shù)的形態(tài),是不是當(dāng)數(shù)據(jù)是順序插入時(shí),樹(shù)的形態(tài)一直處于“右傾”的趨勢(shì)呢?從根本上上看,紅黑樹(shù)并沒(méi)有完全解決二叉查找樹(shù)雖然這個(gè)“右傾”趨勢(shì)遠(yuǎn)沒(méi)有二叉查找樹(shù)退化為線(xiàn)性鏈表那么夸張,但是數(shù)據(jù)庫(kù)中的基本主鍵自增操作,主鍵一般都是數(shù)百萬(wàn)數(shù)千萬(wàn)的,如果紅黑樹(shù)存在這種問(wèn)題,對(duì)于查找性能而言也是巨大的消耗,我們數(shù)據(jù)庫(kù)不可能忍受這種無(wú)意義的等待的。
現(xiàn)在考慮另一種更為嚴(yán)格的自平衡二叉樹(shù) AVL 樹(shù)。因?yàn)?AVL 樹(shù)是個(gè)絕對(duì)平衡的二叉樹(shù),因此他在調(diào)整二叉樹(shù)的形態(tài)上消耗的性能會(huì)更多。
AVL 樹(shù)順序插入 1~7 個(gè)節(jié)點(diǎn),查找 id=7 所要比較節(jié)點(diǎn)的次數(shù)為 3。
AVL 樹(shù)順序插入 1~16 個(gè)節(jié)點(diǎn),查找 id=16 需要比較的節(jié)點(diǎn)數(shù)為 4。從查找效率而言,AVL 樹(shù)查找的速度要高于紅黑樹(shù)的查找效率(AVL 樹(shù)是 4 次比較,紅黑樹(shù)是 6 次比較)。從樹(shù)的形態(tài)看來(lái),AVL 樹(shù)不存在紅黑樹(shù)的“右傾”問(wèn)題。也就是說(shuō),大量的順序插入不會(huì)導(dǎo)致查詢(xún)性能的降低,這從根本上解決了紅黑樹(shù)的問(wèn)題。
總結(jié)一下 AVL 樹(shù)的優(yōu)點(diǎn):
不錯(cuò)的查找性能(O(logn)),不存在極端的低效查找的情況。
可以實(shí)現(xiàn)范圍查找、數(shù)據(jù)排序。
看起來(lái) AVL 樹(shù)作為數(shù)據(jù)查找的數(shù)據(jù)結(jié)構(gòu)確實(shí)很不錯(cuò),但是 AVL 樹(shù)并不適合做 Mysql 數(shù)據(jù)庫(kù)的索引數(shù)據(jù)結(jié)構(gòu),因?yàn)榭紤]一下這個(gè)問(wèn)題:
數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù)的瓶頸在于磁盤(pán) IO,如果使用的是 AVL 樹(shù),我們每一個(gè)樹(shù)節(jié)點(diǎn)只存儲(chǔ)了一個(gè)數(shù)據(jù),我們一次磁盤(pán) IO 只能取出來(lái)一個(gè)節(jié)點(diǎn)上的數(shù)據(jù)加載到內(nèi)存里,那比如查詢(xún) id=7 這個(gè)數(shù)據(jù)我們就要進(jìn)行磁盤(pán) IO 三次,這是多么消耗時(shí)間的。所以我們?cè)O(shè)計(jì)數(shù)據(jù)庫(kù)索引時(shí)需要首先考慮怎么盡可能減少磁盤(pán) IO 的次數(shù)。
磁盤(pán) IO 有個(gè)有個(gè)特點(diǎn),就是從磁盤(pán)讀取 1B 數(shù)據(jù)和 1KB 數(shù)據(jù)所消耗的時(shí)間是基本一樣的,我們就可以根據(jù)這個(gè)思路,我們可以在一個(gè)樹(shù)節(jié)點(diǎn)上盡可能多地存儲(chǔ)數(shù)據(jù),一次磁盤(pán) IO 就多加載點(diǎn)數(shù)據(jù)到內(nèi)存,這就是 B 樹(shù),B+樹(shù)的的設(shè)計(jì)原理了。
B 樹(shù)
下面這個(gè) B 樹(shù),每個(gè)節(jié)點(diǎn)限制最多存儲(chǔ)兩個(gè) key,一個(gè)節(jié)點(diǎn)如果超過(guò)兩個(gè) key 就會(huì)自動(dòng)分裂。比如下面這個(gè)存儲(chǔ)了 7 個(gè)數(shù)據(jù) B 樹(shù),只需要查詢(xún)兩個(gè)節(jié)點(diǎn)就可以知道 id=7 這數(shù)據(jù)的具體位置,也就是兩次磁盤(pán) IO 就可以查詢(xún)到指定數(shù)據(jù),優(yōu)于 AVL 樹(shù)。
下面是一個(gè)存儲(chǔ)了 16 個(gè)數(shù)據(jù)的 B 樹(shù),同樣每個(gè)節(jié)點(diǎn)最多存儲(chǔ) 2 個(gè) key,查詢(xún) id=16 這個(gè)數(shù)據(jù)需要查詢(xún)比較 4 個(gè)節(jié)點(diǎn),也就是經(jīng)過(guò) 4 次磁盤(pán) IO??雌饋?lái)查詢(xún)性能與 AVL 樹(shù)一樣。
但是考慮到磁盤(pán) IO 讀一個(gè)數(shù)據(jù)和讀 100 個(gè)數(shù)據(jù)消耗的時(shí)間基本一致,那我們的優(yōu)化思路就可以改為:盡可能在一次磁盤(pán) IO 中多讀一點(diǎn)數(shù)據(jù)到內(nèi)存。這個(gè)直接反映到樹(shù)的結(jié)構(gòu)就是,每個(gè)節(jié)點(diǎn)能存儲(chǔ)的 key 可以適當(dāng)增加。
當(dāng)我們把單個(gè)節(jié)點(diǎn)限制的 key 個(gè)數(shù)設(shè)置為 6 之后,一個(gè)存儲(chǔ)了 7 個(gè)數(shù)據(jù)的 B 樹(shù),查詢(xún) id=7 這個(gè)數(shù)據(jù)所要進(jìn)行的磁盤(pán) IO 為 2 次。
一個(gè)存儲(chǔ)了 16 個(gè)數(shù)據(jù)的 B 樹(shù),查詢(xún) id=7 這個(gè)數(shù)據(jù)所要進(jìn)行的磁盤(pán) IO 為 2 次。相對(duì)于 AVL 樹(shù)而言磁盤(pán) IO 次數(shù)降低為一半。
所以數(shù)據(jù)庫(kù)索引數(shù)據(jù)結(jié)構(gòu)的選型而言,B 樹(shù)是一個(gè)很不錯(cuò)的選擇。總結(jié)來(lái)說(shuō),B 樹(shù)用作數(shù)據(jù)庫(kù)索引有以下優(yōu)點(diǎn):
優(yōu)秀檢索速度,時(shí)間復(fù)雜度:B 樹(shù)的查找性能等于 O(h*logn),其中 h 為樹(shù)高,n 為每個(gè)節(jié)點(diǎn)關(guān)鍵詞的個(gè)數(shù);
盡可能少的磁盤(pán) IO,加快了檢索速度;
可以支持范圍查找。
5.B+樹(shù)
B 樹(shù)和 B+樹(shù)有什么不同呢?
第一,B 樹(shù)一個(gè)節(jié)點(diǎn)里存的是數(shù)據(jù),而 B+樹(shù)存儲(chǔ)的是索引(地址),所以 B 樹(shù)里一個(gè)節(jié)點(diǎn)存不了很多個(gè)數(shù)據(jù),但是 B+樹(shù)一個(gè)節(jié)點(diǎn)能存很多索引,B+樹(shù)葉子節(jié)點(diǎn)存所有的數(shù)據(jù)。
第二,B+樹(shù)的葉子節(jié)點(diǎn)是數(shù)據(jù)階段用了一個(gè)鏈表串聯(lián)起來(lái),便于范圍查找。
通過(guò) B 樹(shù)和 B+樹(shù)的對(duì)比我們看出,B+樹(shù)節(jié)點(diǎn)存儲(chǔ)的是索引,在單個(gè)節(jié)點(diǎn)存儲(chǔ)容量有限的情況下,單節(jié)點(diǎn)也能存儲(chǔ)大量索引,使得整個(gè) B+樹(shù)高度降低,減少了磁盤(pán) IO。其次,B+樹(shù)的葉子節(jié)點(diǎn)是真正數(shù)據(jù)存儲(chǔ)的地方,葉子節(jié)點(diǎn)用了鏈表連接起來(lái),這個(gè)鏈表本身就是有序的,在數(shù)據(jù)范圍查找時(shí),更具備效率。因此 Mysql 的索引用的就是 B+樹(shù),B+樹(shù)在查找效率、范圍查找中都有著非常不錯(cuò)的性能。
Innodb 引擎和 Myisam 引擎的實(shí)現(xiàn)
Mysql 底層數(shù)據(jù)引擎以插件形式設(shè)計(jì),最常見(jiàn)的是 Innodb 引擎和 Myisam 引擎,用戶(hù)可以根據(jù)個(gè)人需求選擇不同的引擎作為 Mysql 數(shù)據(jù)表的底層引擎。我們剛分析了,B+樹(shù)作為 Mysql 的索引的數(shù)據(jù)結(jié)構(gòu)非常合適,但是數(shù)據(jù)和索引到底怎么組織起來(lái)也是需要一番設(shè)計(jì),設(shè)計(jì)理念的不同也導(dǎo)致了 Innodb 和 Myisam 的出現(xiàn),各自呈現(xiàn)獨(dú)特的性能。
MyISAM 雖然數(shù)據(jù)查找性能極佳,但是不支持事務(wù)處理。Innodb 最大的特色就是支持了 ACID 兼容的事務(wù)功能,而且他支持行級(jí)鎖。Mysql 建立表的時(shí)候就可以指定引擎,比如下面的例子,就是分別指定了 Myisam 和 Innodb 作為 user 表和 user2 表的數(shù)據(jù)引擎。
執(zhí)行這兩個(gè)指令后,系統(tǒng)出現(xiàn)了以下的文件,說(shuō)明這兩個(gè)引擎數(shù)據(jù)和索引的組織方式是不一樣的。
Innodb 創(chuàng)建表后生成的文件有:
frm:創(chuàng)建表的語(yǔ)句
idb:表里面的數(shù)據(jù)+索引文件
Myisam 創(chuàng)建表后生成的文件有
frm:創(chuàng)建表的語(yǔ)句
MYD:表里面的數(shù)據(jù)文件(myisam data)
MYI:表里面的索引文件(myisam index)
從生成的文件看來(lái),這兩個(gè)引擎底層數(shù)據(jù)和索引的組織方式并不一樣,MyISAM 引擎把數(shù)據(jù)和索引分開(kāi)了,一人一個(gè)文件,這叫做非聚集索引方式;Innodb 引擎把數(shù)據(jù)和索引放在同一個(gè)文件里了,這叫做聚集索引方式。下面將從底層實(shí)現(xiàn)角度分析這兩個(gè)引擎是怎么依靠 B+樹(shù)這個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)組織引擎實(shí)現(xiàn)的。
MyISAM 引擎的底層實(shí)現(xiàn)(非聚集索引方式)
MyISAM 用的是非聚集索引方式,即數(shù)據(jù)和索引落在不同的兩個(gè)文件上。MyISAM 在建表時(shí)以主鍵作為 KEY 來(lái)建立主索引 B+樹(shù),樹(shù)的葉子節(jié)點(diǎn)存的是對(duì)應(yīng)數(shù)據(jù)的物理地址。我們拿到這個(gè)物理地址后,就可以到 MyISAM 數(shù)據(jù)文件中直接定位到具體的數(shù)據(jù)記錄了。
當(dāng)我們?yōu)槟硞€(gè)字段添加索引時(shí),我們同樣會(huì)生成對(duì)應(yīng)字段的索引樹(shù),該字段的索引樹(shù)的葉子節(jié)點(diǎn)同樣是記錄了對(duì)應(yīng)數(shù)據(jù)的物理地址,然后也是拿著這個(gè)物理地址去數(shù)據(jù)文件里定位到具體的數(shù)據(jù)記錄。
Innodb 引擎的底層實(shí)現(xiàn)(聚集索引方式)
InnoDB 是聚集索引方式,因此數(shù)據(jù)和索引都存儲(chǔ)在同一個(gè)文件里。首先 InnoDB 會(huì)根據(jù)主鍵 ID 作為 KEY 建立索引 B+樹(shù),如左下圖所示,而 B+樹(shù)的葉子節(jié)點(diǎn)存儲(chǔ)的是主鍵 ID 對(duì)應(yīng)的數(shù)據(jù),比如在執(zhí)行 select * from user_info where id=15 這個(gè)語(yǔ)句時(shí),InnoDB 就會(huì)查詢(xún)這顆主鍵 ID 索引 B+樹(shù),找到對(duì)應(yīng)的 user_name='Bob'。
這是建表的時(shí)候 InnoDB 就會(huì)自動(dòng)建立好主鍵 ID 索引樹(shù),這也是為什么 Mysql 在建表時(shí)要求必須指定主鍵的原因。當(dāng)我們?yōu)楸砝锬硞€(gè)字段加索引時(shí) InnoDB 會(huì)怎么建立索引樹(shù)呢?比如我們要給 user_name 這個(gè)字段加索引,那么 InnoDB 就會(huì)建立 user_name 索引 B+樹(shù),節(jié)點(diǎn)里存的是 user_name 這個(gè) KEY,葉子節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)的是主鍵 KEY。注意,葉子存儲(chǔ)的是主鍵 KEY!拿到主鍵 KEY 后,InnoDB 才會(huì)去主鍵索引樹(shù)里根據(jù)剛在 user_name 索引樹(shù)找到的主鍵 KEY 查找到對(duì)應(yīng)的數(shù)據(jù)。
問(wèn)題來(lái)了,為什么 InnoDB 只在主鍵索引樹(shù)的葉子節(jié)點(diǎn)存儲(chǔ)了具體數(shù)據(jù),但是其他索引樹(shù)卻不存具體數(shù)據(jù)呢,而要多此一舉先找到主鍵,再在主鍵索引樹(shù)找到對(duì)應(yīng)的數(shù)據(jù)呢?
其實(shí)很簡(jiǎn)單,因?yàn)?InnoDB 需要節(jié)省存儲(chǔ)空間。一個(gè)表里可能有很多個(gè)索引,InnoDB 都會(huì)給每個(gè)加了索引的字段生成索引樹(shù),如果每個(gè)字段的索引樹(shù)都存儲(chǔ)了具體數(shù)據(jù),那么這個(gè)表的索引數(shù)據(jù)文件就變得非常巨大(數(shù)據(jù)極度冗余了)。從節(jié)約磁盤(pán)空間的角度來(lái)說(shuō),真的沒(méi)有必要每個(gè)字段索引樹(shù)都存具體數(shù)據(jù),通過(guò)這種看似“多此一舉”的步驟,在犧牲較少查詢(xún)的性能下節(jié)省了巨大的磁盤(pán)空間,這是非常有值得的。
在進(jìn)行 InnoDB 和 MyISAM 特點(diǎn)對(duì)比時(shí)談到,MyISAM 查詢(xún)性能更好,從上面索引文件數(shù)據(jù)文件的設(shè)計(jì)來(lái)看也可以看出原因:MyISAM 直接找到物理地址后就可以直接定位到數(shù)據(jù)記錄,但是 InnoDB 查詢(xún)到葉子節(jié)點(diǎn)后,還需要再查詢(xún)一次主鍵索引樹(shù),才可以定位到具體數(shù)據(jù)。等于 MyISAM 一步就查到了數(shù)據(jù),但是 InnoDB 要兩步,那當(dāng)然 MyISAM 查詢(xún)性能更高。
本文首先探討了哪種數(shù)據(jù)結(jié)構(gòu)更適合作為 Mysql 底層索引的實(shí)現(xiàn),然后再介紹了 Mysql 兩種經(jīng)典數(shù)據(jù)引擎 MyISAM 和 InnoDB 的底層實(shí)現(xiàn)。最后再總結(jié)一下什么時(shí)候需要給你的表里的字段加索引吧:
較頻繁的作為查詢(xún)條件的字段應(yīng)該創(chuàng)建索引;
唯一性太差的字段不適合單獨(dú)創(chuàng)建索引,即使該字段頻繁作為查詢(xún)條件;
更新非常頻繁的字段不適合創(chuàng)建索引。
到此這篇關(guān)于深入理解 MySQL 索引底層原理的文章就介紹到這了,更多相關(guān)MySQL 索引底層原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL常用SQL語(yǔ)句總結(jié)包含復(fù)雜SQL查詢(xún)
今天小編就為大家分享一篇關(guān)于MySQL常用SQL語(yǔ)句總結(jié)包含復(fù)雜SQL查詢(xún),小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02MySQL8.0設(shè)置遠(yuǎn)程訪(fǎng)問(wèn)權(quán)限的方法
這篇文章主要介紹了MySQL8.0設(shè)置遠(yuǎn)程訪(fǎng)問(wèn)權(quán)限的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11MySQL字符串轉(zhuǎn)數(shù)字的3種方式實(shí)例
這篇文章主要給大家介紹了關(guān)于MySQL字符串轉(zhuǎn)數(shù)字的3種方式,在使用mysql中經(jīng)常遇到要將字符串?dāng)?shù)字轉(zhuǎn)換成可計(jì)算數(shù)字,文中給出了詳細(xì)的代碼示例和圖文介紹,需要的朋友可以參考下2023-08-08mysql語(yǔ)句實(shí)現(xiàn)簡(jiǎn)單的增、刪、改、查操作示例
這篇文章主要介紹了mysql語(yǔ)句實(shí)現(xiàn)簡(jiǎn)單的增、刪、改、查操作,結(jié)合實(shí)例形式分析總結(jié)了mysql語(yǔ)句實(shí)現(xiàn)數(shù)據(jù)庫(kù)與表的創(chuàng)建、刪除以及增刪改查等常見(jiàn)操作技巧,需要的朋友可以參考下2019-05-05MySQL利用AES_ENCRYPT()與AES_DECRYPT()加解密的正確方法示例
MySQL中AES_ENCRYPT('密碼','鑰匙')函數(shù)可以對(duì)字段值做加密處理,AES_DECRYPT(表的字段名字,'鑰匙')函數(shù)解密處理,下面這篇文章主要給大家介紹了關(guān)于MySQL利用AES_ENCRYPT()與AES_DECRYPT()加解密的正確方法,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下。2017-08-08關(guān)于mysql數(shù)據(jù)庫(kù)連接編碼問(wèn)題
這篇文章主要介紹了關(guān)于mysql數(shù)據(jù)庫(kù)連接編碼問(wèn)題,默認(rèn)的編碼和數(shù)據(jù)庫(kù)表中的數(shù)據(jù)使用的編碼是不一致的,如果是中文,那么在數(shù)據(jù)庫(kù)中執(zhí)行時(shí)已經(jīng)是亂碼了,需要的朋友可以參考下2023-04-04