MySQL三大知識(shí)點(diǎn)——索引

索引浅悉,類似于圖書(shū)目錄闽颇,可以根據(jù)目錄某個(gè)頁(yè)碼立即找到對(duì)應(yīng)的內(nèi)容。
索引的有點(diǎn)顯而易見(jiàn):(有可能)提升查詢效率
同時(shí)也有缺點(diǎn):增大數(shù)據(jù)庫(kù)空間占用雏掠,降低表更新的效率

從實(shí)現(xiàn)上來(lái)說(shuō)斩祭,索引可以分為兩種:聚集索引、非聚集索引乡话。
說(shuō)到索引的實(shí)現(xiàn)摧玫,不得不提B+樹(shù),提到B+樹(shù)绑青,就要先搞明白B樹(shù)诬像。

一、B樹(shù)與B+樹(shù)

1.B樹(shù)

B樹(shù)是一種多路平衡查找樹(shù)闸婴,一個(gè)高度為m的B樹(shù)有以下幾個(gè)特點(diǎn):
1.根節(jié)點(diǎn)至少有兩個(gè)子節(jié)點(diǎn)坏挠;
2.每個(gè)中間節(jié)點(diǎn)都包含k-1個(gè)元素和k個(gè)子節(jié)點(diǎn),其中m/2 <= k <= m掠拳;
3.每個(gè)葉節(jié)點(diǎn)包含k-1個(gè)元素癞揉,其中m/2 <= k <= m;
4.所有的葉節(jié)點(diǎn)都位于同一層溺欧;
5.每個(gè)節(jié)點(diǎn)中的元素從小到大排列喊熟,節(jié)點(diǎn)中k-1個(gè)元素正好是k個(gè)子節(jié)點(diǎn)所包含元素的值域劃分。

B樹(shù)
查找

MySQL將數(shù)據(jù)按照頁(yè)來(lái)存儲(chǔ)姐刁,默認(rèn)一頁(yè)為16KB芥牌,查詢時(shí),不會(huì)只加載某一條數(shù)據(jù)聂使,而是將目標(biāo)所在的頁(yè)都加載到PageCache中壁拉。B樹(shù)中,一個(gè)節(jié)點(diǎn)代表了一頁(yè)柏靶,查找的時(shí)候弃理,每經(jīng)過(guò)一個(gè)節(jié)點(diǎn)就需要一次磁盤(pán)IO,可以發(fā)現(xiàn)屎蜓,以上圖中的B樹(shù)為例痘昌,查找的最壞情況需要3次磁盤(pán)IO,即樹(shù)的高度炬转。

插入

B樹(shù)還有一個(gè)特點(diǎn)辆苔,自平衡,這也使得其在插入新數(shù)據(jù)的時(shí)候比較復(fù)雜扼劈。還是用上圖的B樹(shù)舉例驻啤,假設(shè)我們要插入一個(gè)新值4。自頂向下查找到應(yīng)該插入的位置荐吵,發(fā)現(xiàn)應(yīng)該在3,5之間骑冗。


插入4

節(jié)點(diǎn)3赊瞬,5已經(jīng)是兩元素節(jié)點(diǎn),無(wú)法再增加沐旨。父親節(jié)點(diǎn) 2森逮, 6 也是兩元素節(jié)點(diǎn),也無(wú)法再增加磁携。根節(jié)點(diǎn)9是單元素節(jié)點(diǎn),可以升級(jí)為兩元素節(jié)點(diǎn)良风。于是拆分節(jié)點(diǎn)3谊迄,5與節(jié)點(diǎn)2,6烟央,讓根節(jié)點(diǎn)9升級(jí)為兩元素節(jié)點(diǎn)4统诺,9。節(jié)點(diǎn)6獨(dú)立為根節(jié)點(diǎn)的第二個(gè)孩子疑俭。


自平衡
刪除

再來(lái)看看刪除粮呢,假設(shè)我們要?jiǎng)h除11這個(gè)數(shù)據(jù)。


刪除11

刪除11后钞艇,節(jié)點(diǎn)12只有一個(gè)孩子啄寡,不符合B樹(shù)規(guī)范。因此找出12,13,15三個(gè)節(jié)點(diǎn)的中位數(shù)13哩照,取代節(jié)點(diǎn)12挺物,而節(jié)點(diǎn)12自身下移成為第一個(gè)孩子。(這個(gè)過(guò)程稱為左旋)


左旋

最終結(jié)果

B樹(shù)主要應(yīng)用于文件系統(tǒng)及某些數(shù)據(jù)庫(kù)索引飘弧,比如MongoDB识藤。對(duì)于同等數(shù)量的數(shù)據(jù),相較于二叉查找樹(shù)次伶,B樹(shù)的每一層能存放更多數(shù)據(jù)痴昧,二叉樹(shù)比較“瘦高”,而B(niǎo)樹(shù)比較“胖矮”冠王,這樣能有效減少查詢過(guò)程中磁盤(pán)IO的次數(shù)赶撰。

2.B+樹(shù)

B+樹(shù)在B樹(shù)的基礎(chǔ)上做了改進(jìn)。先來(lái)看看B+樹(shù)的特征:
1.有k個(gè)子樹(shù)的中間節(jié)點(diǎn)包含有k個(gè)元素(B樹(shù)中是k-1個(gè)元素)版确,每個(gè)元素不保存數(shù)據(jù)扣囊,只用來(lái)索引,所有數(shù)據(jù)都保存在葉子節(jié)點(diǎn)绒疗。
2.所有的葉子結(jié)點(diǎn)中包含了全部元素的信息侵歇,及指向含這些元素記錄的指針,且葉子結(jié)點(diǎn)本身依關(guān)鍵字的大小自小而大順序鏈接吓蘑。
3.所有的中間節(jié)點(diǎn)元素都同時(shí)存在于子節(jié)點(diǎn)惕虑,在子節(jié)點(diǎn)元素中是最大(或最蟹爻濉)元素。

B+樹(shù)

圖中的B+樹(shù)溃蔫,父節(jié)點(diǎn)中的元素是各子節(jié)點(diǎn)中的最大元素健提。可以發(fā)現(xiàn)伟叛,根節(jié)點(diǎn)的最大值15私痹,也是整個(gè)樹(shù)的最大值;此外统刮,所有的葉節(jié)點(diǎn)包含了全量元素紊遵,每個(gè)葉節(jié)點(diǎn)都有一個(gè)指針指向下一個(gè)葉節(jié)點(diǎn),形成了一個(gè)有序鏈表侥蒙。

除此之外暗膜,還需要了解一個(gè)概念——衛(wèi)星數(shù)據(jù)(Satellite Data)。所謂衛(wèi)星數(shù)據(jù)鞭衩,指的是索引元素所指向的數(shù)據(jù)記錄学搜,比如數(shù)據(jù)庫(kù)中的某一行。B樹(shù)中论衍,無(wú)論是中間節(jié)點(diǎn)還是葉節(jié)點(diǎn)瑞佩,都帶有衛(wèi)星數(shù)據(jù)。這個(gè)特點(diǎn)會(huì)導(dǎo)致中間節(jié)點(diǎn)不能存儲(chǔ)大量的索引饲齐。

B樹(shù)

而B(niǎo)+樹(shù)針對(duì)這個(gè)做了優(yōu)化钉凌,只有葉節(jié)點(diǎn)帶有衛(wèi)星數(shù)據(jù),中間節(jié)點(diǎn)只包含索引元素和指針捂人。


B+樹(shù)

我們假設(shè)一個(gè)非頁(yè)子節(jié)點(diǎn)是 16kb御雕,每個(gè)索引,即主鍵是 bigint滥搭,即 8b酸纲,指針為 8b。那么每頁(yè)能存儲(chǔ)大約 1000 個(gè)索引(16KB / (8B + 8B))瑟匆。
而一顆 3 層的 B+樹(shù)能夠存儲(chǔ)多少索引呢闽坡?如下圖:

索引

大約能夠存儲(chǔ) 10 億個(gè)索引。由此可見(jiàn)愁溜,相比于B樹(shù)疾嗅,B+樹(shù)更加矮胖,查詢的時(shí)候(平均情況下)磁盤(pán)IO的次數(shù)更少冕象。

除此之外代承,范圍查詢時(shí),B樹(shù)找到范圍起始的索引元素后渐扮,只能通過(guò)中序遍歷的方式论悴,過(guò)程復(fù)雜掖棉;而B(niǎo)+樹(shù)由于葉節(jié)點(diǎn)全量的元素形成了一個(gè)鏈表,方便快捷膀估。

相比較于B樹(shù)幔亥,B+樹(shù)實(shí)現(xiàn)索引有以下三個(gè)特點(diǎn):1.更少的磁盤(pán)IO;2.查詢性能穩(wěn)定(因?yàn)镮O次數(shù)總等于樹(shù)高)察纯;3.范圍查詢簡(jiǎn)便帕棉。

二、索引分類

1.單列索引 與 復(fù)合索引

只包含一個(gè)字段的索引叫做單列索引捐寥,包含兩個(gè)或以上字段的索引叫做復(fù)合索引(或組合索引)笤昨。建立復(fù)合索引時(shí),字段的順序極其重要握恳。
下面這個(gè)SQL語(yǔ)句在 列X,列Y捺僻,列Z 上建立了一個(gè)復(fù)合索引乡洼。

CREATE INDEX 索引名 ON 表名(列名X, 列名Y, 列名Z);

其實(shí)這相當(dāng)于建立了三個(gè)索引,分別是:
1匕坯、單列索引(列X) 2束昵、復(fù)合索引(列X, 列Y) 3、復(fù)合索引(列X葛峻,列Y锹雏,列Z)。

2.唯一索引 與 主鍵

唯一索引是在表上一個(gè)或者多個(gè)字段組合建立的索引术奖,這個(gè)(或這幾個(gè))字段的值組合起來(lái)在表中不可以重復(fù)礁遵。一張表可以建立任意多個(gè)唯一索引,但一般只建立一個(gè)采记。

主鍵是一種特殊的唯一索引佣耐,區(qū)別在于,唯一索引列允許null值唧龄,而主鍵列不允許為null值兼砖。一張表最多建立一個(gè)主鍵,也可以不建立主鍵既棺。

3.聚簇索引讽挟、非聚簇索引

聚簇索引的葉子節(jié)點(diǎn)就是數(shù)據(jù)節(jié)點(diǎn),而非聚簇索引的葉子節(jié)點(diǎn)仍然是索引節(jié)點(diǎn)丸冕,只不過(guò)有指向?qū)?yīng)數(shù)據(jù)塊的指針耽梅。通常我們建表的時(shí)候,會(huì)指定一個(gè)字段為主鍵晨仑,主鍵唯一且不能為空褐墅,一般情況下主鍵就是聚簇索引拆檬。一張表只允許存在一個(gè)聚簇索引,因?yàn)檎鎸?shí)數(shù)據(jù)的物理順序只能有一種妥凳。如果一張表上還沒(méi)有聚簇索引竟贯,為它新創(chuàng)建聚簇索引時(shí),就需要對(duì)已有數(shù)據(jù)重新進(jìn)行排序逝钥,所以對(duì)表進(jìn)行修改速度較慢是聚簇索引的缺點(diǎn)屑那,對(duì)于經(jīng)常更新的列不宜建立聚簇索引。

我們總說(shuō)的數(shù)據(jù)庫(kù)調(diào)優(yōu)的手段之一——建索引艘款,通常指的是非聚簇索引持际。一張表可以建立任意多個(gè)索引,每個(gè)索引可以是任意多個(gè)字段的組合哗咆。索引可能會(huì)提高查詢速度(如果查詢時(shí)使用了索引)蜘欲,但一定會(huì)減慢寫(xiě)入速度,因?yàn)槊看螌?xiě)入時(shí)都需要更新索引晌柬,所以索引只應(yīng)該加在經(jīng)常需要搜索的列上姥份,不要加在寫(xiě)多讀少的列上。

執(zhí)行某條查詢SQL年碘,從非聚簇索引到聚簇索引澈歉,再到數(shù)據(jù)節(jié)點(diǎn),流程如下:

不管以任何方式查詢表屿衅, 最終都會(huì)利用主鍵通過(guò)聚簇索引來(lái)定位到數(shù)據(jù)埃难, 聚簇索引(主鍵)是通往真實(shí)數(shù)據(jù)所在的唯一路徑。然而凡事都有例外涤久,有一種非主流的方式可以不通過(guò)聚簇索引就能查詢出所需要的數(shù)據(jù)涡尘,這就是覆蓋索引。當(dāng)為字段建立索引以后拴竹, 字段中的內(nèi)容會(huì)被同步到索引之中悟衩, 如果為一個(gè)索引指定兩個(gè)字段, 那么這個(gè)兩個(gè)字段的內(nèi)容都會(huì)被同步至索引之中栓拜。

先看下面這個(gè)SQL語(yǔ)句

-- 建立索引
create index index_birthday_and_user_name on user_info(birthday, user_name);
-- 查詢生日在1991年11月1日出生用戶的用戶名
select user_name from user_info where birthday = '1991-11-1'

這句SQL語(yǔ)句的執(zhí)行過(guò)程如下:

通過(guò)非聚集索引index_birthday_and_user_name查找birthday等于1991-11-1的葉節(jié)點(diǎn)的內(nèi)容座泳,然而, 葉節(jié)點(diǎn)中除了有user_name表主鍵ID的值以外幕与, user_name字段的值也在里面挑势, 因此不需要通過(guò)主鍵ID值的查找數(shù)據(jù)行的真實(shí)所在, 直接取得葉節(jié)點(diǎn)中user_name的值返回即可啦鸣。 通過(guò)這種覆蓋索引直接查找的方式潮饱, 可以省略不使用覆蓋索引查找的后面兩個(gè)步驟, 大大的提高了查詢性能诫给。

4.其他

其他索引的類型還有外鍵索引香拉、全文索引等啦扬,這里簡(jiǎn)單帶過(guò),不再展開(kāi)來(lái)講凫碌。

外鍵索引:只有InnoDB類型的表才可以使用外鍵索引享扔,保證數(shù)據(jù)的一致性捏雌、完整性和實(shí)現(xiàn)級(jí)聯(lián)操作岩灭。

全文索引:MySQL 自帶的全文索引只能用于 InnoDB雀摘、MyISAM ,并且只能對(duì)英文進(jìn)行全文檢索苦掘,一般使用全文索引引擎(ES换帜,Solr)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹤啡,一起剝皮案震驚了整個(gè)濱河市惯驼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌递瑰,老刑警劉巖跳座,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異泣矛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)禾蚕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)您朽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人换淆,你說(shuō)我怎么就攤上這事哗总。” “怎么了倍试?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵讯屈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我县习,道長(zhǎng)涮母,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任躁愿,我火速辦了婚禮叛本,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彤钟。我一直安慰自己来候,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布逸雹。 她就那樣靜靜地躺著营搅,像睡著了一般云挟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上转质,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天园欣,我揣著相機(jī)與錄音,去河邊找鬼峭拘。 笑死俊庇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸡挠。 我是一名探鬼主播辉饱,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拣展!你這毒婦竟也來(lái)了彭沼?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤备埃,失蹤者是張志新(化名)和其女友劉穎姓惑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體按脚,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡于毙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辅搬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唯沮。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖堪遂,靈堂內(nèi)的尸體忽然破棺而出介蛉,到底是詐尸還是另有隱情,我是刑警寧澤溶褪,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布币旧,位于F島的核電站,受9級(jí)特大地震影響猿妈,放射性物質(zhì)發(fā)生泄漏吹菱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一于游、第九天 我趴在偏房一處隱蔽的房頂上張望毁葱。 院中可真熱鬧,春花似錦贰剥、人聲如沸倾剿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)前痘。三九已至凛捏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芹缔,已是汗流浹背坯癣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留最欠,地道東北人示罗。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像芝硬,于是被迫代替她去往敵國(guó)和親蚜点。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345