索引底層原理

create table t1 (
    a int primary key,
    b int,
    c int,
    d int,
    e varchar(20)
) engine = innodb;

insert into t1 value(4, 3, 1, 1, 'd');
insert into t1 value(1, 1, 1, 1, 'a');
insert into t1 value(8, 8, 8, 8, 'h');
insert into t1 value(2, 2, 2, 2, 'b');

insert into t1 value(5, 2, 3, 5, 'e');
insert into t1 value(3, 3, 2, 2, 'c');
insert into t1 value(7, 4, 5, 5, 'g');
insert into t1 value(6, 6, 4, 4, 'f');

1、頁

頁是InnoBD存儲引摯管理數據庫的最小磁盤單位(邏輯單位)未状,遵循計算機的局部性原理

1窥妇、局部性原理

局部性原理又表現為:時間局部性和空間局部性。

  • 時間局部性是指如果程序中的某條指令一旦執(zhí)行娩践,則不久之后該指令可能再次被執(zhí)行活翩;如果某數據被訪問,則不久之后該數據可能再次被訪問翻伺。
  • 空間局部性是指一旦程序訪問了某個存儲單元材泄,則不久之后,其附近的存儲單元也將被訪問吨岭。
2拉宗、磁盤IO與預讀

考慮到磁盤IO是非常高昂的操作,計算機操作系統(tǒng)做了一些優(yōu)化,當一次IO時旦事,不光把當前磁盤地址的數據魁巩,而是把相鄰的數據也都讀取到內存緩沖區(qū)內,因為局部預讀性原理告訴我們姐浮,當計算機訪問一個地址的數據的時候谷遂,與其相鄰的數據也會很快被訪問到。每一次IO讀取的數據我們稱之為一頁(page)卖鲤。具體一頁有多大數據跟操作系統(tǒng)有關肾扰,一般為4k或8k,也就是我們讀取一頁內的數據時候蛋逾,實際上才發(fā)生了一次IO集晚,這個理論對于索引的數據結構設計非常有幫助。(在InnoDB一頁的大小是16KB)

3区匣、InnoDB數據頁由以下7個部分組成
  • FIle Header(文件頭)
  • Page Header(頁頭)
  • Infimun 和 Supremum Records
  • User Records(用戶記錄偷拔,即行記錄)
  • Free Space(空閑空間)
  • Page Directory(頁目錄)
  • File Trailer(文件結尾信息)
image.png

特別說明:
①:主鍵索引,b+樹中會存儲完整記錄亏钩,即每一個頁的每個數據項記錄的是某一個行的完整信息
②:二級索引条摸,b+數中不會存在完整記錄,即每一頁的每個數據項記錄的是某一行的主鍵索引(注意铸屉,這里記錄的是一個索引钉蒲,還需要回表到主鍵索引對應的B+樹去查)
③:頁目錄的作用:通過槽對用戶數據區(qū)域的數據項進行劃分,以多少個數據項為一組彻坛,而槽記錄的是該組第一個數據項的地址偏移量顷啼。當查找一個數據時,具體的執(zhí)行流程在下面
④:用戶數據區(qū)域的數據項是通過某個值進行排序的昌屉,主鍵索引通過主鍵值排序钙蒙,其他二級索引通過特定的索引值排序

4、在某一頁中的查找數據的執(zhí)行流程

通過某個索引值去查找數據時间驮,找到該頁時躬厌,通過二分法在頁目錄中找到對應的槽,在槽維護的區(qū)間中逐個遍歷尋找竞帽,找到后返回

例如:

select * from t1 where a = 3
image.png

插入操作
在圖中扛施,加入用戶數據區(qū)域只能存4條數據,當插入(5,2,3,5,'e')時屹篓,會把(5,2,3,5,'e')插入到該頁中疙渣,而將(8,8,8,8,'h')調整到下一頁

image.png

兩頁數據的存儲情況

image.png

2、InnoDB 存儲引擎使用B+樹結構

image.png

如果數據中數據極少堆巧,只有一兩條記錄妄荔,完全沒有必要用B+樹泼菌,B+樹是需要去維護的,需要一定的成本啦租,占用一定的內存哗伯,B+樹是隨著數據的增加慢慢生成出來的,當數據進行插入的時候篷角,是根據B+樹的特性進行插入焊刹,慢慢呈現出一棵B+樹

其中,每個大框框都是代表一個頁内地,指針指向的是一個頁

1、索引的本質是什么

索引是mysql高效去獲取數據并排好序的數據結構赋除,數據結構指的是組織數據的方式阱缓。例如,主鍵值數據是以B+樹進行組織的举农,因此這個B+樹就是一個主鍵索引荆针。

每一個索引在 InnoDB 里面對應一棵 B+ 樹。

**颁糟,該B+樹的葉結點是存放具體數據的航背,

2、聚簇索引 與 非聚簇索引
(1)聚簇索引

1棱貌、以 InnoDB 作為存儲引擎的表玖媚,表中的數據都會有一個主鍵,即使你不創(chuàng)建主鍵婚脱,系統(tǒng)也會幫你創(chuàng)建一個隱式的主鍵今魔。這是因為 InnoDB 是把數據存放在 B+ 樹中的,而 B+ 樹的鍵值就是主鍵障贸,在 B+ 樹的葉子節(jié)點中错森,存儲了表中所有的數據。

2篮洁、即每個表都會有一棵通過主鍵值建立出來的B+樹(主鍵索引)涩维,主鍵索引的葉子節(jié)點存的是整行數據。在 InnoDB 里袁波,主鍵索引也被稱為聚簇索引

(2)非聚簇索引

以主鍵以外的列值作為鍵值構建的 B+ 樹索引瓦阐,且非主鍵索引的葉子節(jié)點內容是主鍵的值,在 InnoDB 里篷牌,我們稱之為非聚集索引垄分。也稱 非主鍵索引 或者 二級索引

3、當某個表中如果沒有主鍵怎么辦娃磺?

如果沒有主鍵索引薄湿,就把唯一索引作為主鍵索引;如果沒有唯一索引,則會對每一行生成一個隱式字段row_id豺瘤,通過他們作為主鍵索引

注意:必須需要一個唯一確定該表的主鍵索引吆倦,整棵B+樹是通過主鍵索引的排序規(guī)律進行插入,尋找的

4坐求、聚簇索引(主鍵索引)例子

(1)精確查詢

explain select * from t1 where a = 1;

分析:由于a是主鍵蚕泽,因此可以通過主鍵索引進行查詢

(2)范圍查詢

explain select * from t1 where a > 1;

分析:也是通過主鍵索引進行查詢,查到a = 1的位置對應的葉結點桥嗤,通過葉結點繼續(xù)往后找就可以了

5须妻、非聚簇索引(主鍵索引)例子

(1)在只有主鍵索引的情況下,查找如下

explain select * from t1 where b = 2 and c = 3 and d = 5;

分析:會通過全表掃描的方式查詢泛领,即通過主鍵索引搜到最小的頁荒吏,從左往右掃描

(2)如果上面的查詢語句是我們經常使用的查詢,我們可以添加一個索引渊鞋,再通過該索引idx_t1_bcd進行查詢绰更,該索引idx_t1_bcd也會生成一棵B+樹,存的數據是該行的主鍵锡宋。同時數據的排序規(guī)則是儡湾,先對b排序,相同再對c排序执俩,相同再對d排序徐钠。如圖所示

create index idx_t1_bcd on t1(b, c, d);//建立一個bcd索引

explain select * from t1 where b = 2 and c = 3 and d = 5;
image.png

分析:通過索引idx_t1_bcd找到b = 2,c = 3役首,d = 5對應是數據是主鍵值是5丹皱,即a = 5,再通過該主鍵值繼續(xù)通過主鍵索引去尋找具體的行

注意:非聚簇索引存儲的是索引的數據(b宋税,c摊崭,d)以及主鍵是數據(a),要尋找其他的數據需要繼續(xù)通過聚簇索引(主鍵索引)查找杰赛,這樣的操作叫做回表(特別重要)

覆蓋索引

InnoDB存儲引擎支持覆蓋索引(covering index呢簸,或稱索引覆蓋),即從輔助索引中就可以得到查詢記錄乏屯,而不需要查詢聚集索引中的記錄根时。

使用覆蓋索引的一個好處是:輔助索引不包含整行記錄的所有信息,故其大小要遠小于聚集索引辰晕,因此可以減少大量的IO操作

(3)如果條件也是b蛤迎,c,d含友,只不過順序不同替裆,會怎么樣查詢呢校辩?

explain select * from t1 where c = 1 and d = 1 and b = 1;

分析:也是會通過索引idx_t1_bcd進行查詢,因為查詢的時候在Server層會經過一個優(yōu)化器辆童,該優(yōu)化器會對條件c宜咒,d,b進行調優(yōu)再決定使用哪個索引去查詢把鉴,最終選擇索引idx_t1_bcd進行查詢(例如故黑,可以通過條件順序調整成固定順序b,c庭砍,d的形式)

(4)如果條件只是c和d场晶,會怎么樣查詢呢?怠缸?

explain select * from t1 where c = 1 and d = 1 ;

分析:會通過全表掃描進行查詢诗轻,原因是因為b不知道,導致如果用索引idx_t1_bcd去查詢的時候凯旭,不知道是向左邊找還是向右邊找概耻,因此只能全表掃描

這就是最左前綴原則

B+ 樹這種索引結構使套,可以利用索引的“最左前綴”罐呼,來定位記錄。如果想使用哪個索引侦高,一定要提供這個字段的最左邊的字段嫉柴,因為是按照最左邊的字段順序排序的

(5)如果條件只是b和d,會怎么樣查詢呢奉呛?计螺?

explain select * from t1 where b = 1 and d = 1 ;

分析:先通過索引idx_t1_bcd尋找到b=1的第一個頁,因為哪些符合還不知道瞧壮,因此在b=1的第一個頁中開始往后遍歷登馒,當每一次都滿足d也等于1(例如111),則拿到該數據項的主鍵值去回表查詢咆槽,直到b不等于1為止就停止

這就是索引下推

在找到最左前綴對應的ID時陈轿,在非聚簇索引中開始往后找,滿足條件的則進行回表(并不是每個都回表秦忿,只有滿足條件才回表查詢)

在 MySQL 5.6 之前麦射,只能從 ID3 開始一個個回表。到主鍵索引上找出數據行灯谣,再對比字段值潜秋。
而 MySQL 5.6 引入的索引下推優(yōu)化(index condition pushdown), 可以在索引遍歷過程中胎许,對索引中包含的字段先做判斷峻呛,直接過濾掉不滿足條件的記錄罗售,減少回表次數。

(6)如果條件只是b和e杀饵,會怎么樣查詢呢莽囤??

explain select * from t1 where b = 1 and e = 1 ;

分析:先通過索引idx_t1_bcd尋找到 b=1 的第一個頁的第一個主鍵值切距,然后再在索引idx_t1_bcd中往后掃朽缎,每當滿足b = 1的就回表查詢,回表查詢后發(fā)現e=1則返回數據谜悟,

下面的分析是錯誤的话肖,由于主鍵索引是以a為鍵值,b = 1并不是在主鍵索引中是連續(xù)的葡幸,因此是錯誤的
先通過索引idx_t1_bcd尋找到 b=1 的第一個頁的第一個主鍵值最筒,再進行回表,找到主鍵索引中第一個滿足條件的頁的第一項蔚叨,從左往右掃描床蜘,直到b不等于1為止

(7)如果條件只是b > 1,會怎么樣查詢呢蔑水?邢锯?

explain select * from t1 where b > 1;

分析:優(yōu)化器會分析情況一和情況二的性能,再做出決策
情況一:
先通過索引idx_t1_bcd尋找到b=1的第一個頁的第一個主鍵值搀别,再在索引idx_t1_bcd中往后掃丹擎,每當滿足b > 1的就回表查詢,(和6一樣)

情況二:
可以通過主鍵索引進行全表查詢

(8)如果條件如下

explain select c from t1 where b = 1;

分析:直接在索引idx_t1_bcd找到第一個b = 1的數據項歇父,從左往右掃描蒂培,然后直接返回即可(覆蓋索引)

(9)如果條件如下

create index idx_t1_e on t1(e);//建立一個e索引

explain select * from t1 where a = 1; (1)
explain select * from t1 where a = '1'; (2)
explain select * from t1 where e = 1;  (3)
explain select * from t1 where e = '1'; (4)

可以很明確指定(1)會走a的索引,(4)會走e的索引
引理:字符串可以自動轉數字榜苫,而數字不能自動轉字符串
因此a = '1'會自動轉換成a = 1护戳,因此(2)也是走a的索引
然而e = 1不會自動轉成‘1’,因此(4)只能e = 1去全表掃描垂睬,將查到的字符串e先將它轉成數字媳荒,再和1比較

字符串作為索引去建一棵B+樹,是通過某一個特定的規(guī)律進行字符串排序的羔飞,也就是說e = 1不能走idx_t1_e索引去搜肺樟,可能idx_t1_e索引的順序是1,3,2,并非按照1,2,3的順序排列

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末逻淌,一起剝皮案震驚了整個濱河市么伯,隨后出現的幾起案子,更是在濱河造成了極大的恐慌卡儒,老刑警劉巖田柔,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俐巴,死亡現場離奇詭異,居然都是意外死亡硬爆,警方通過查閱死者的電腦和手機欣舵,發(fā)現死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缀磕,“玉大人缘圈,你說我怎么就攤上這事⊥嗖希” “怎么了糟把?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長牲剃。 經常有香客問我遣疯,道長,這世上最難降的妖魔是什么凿傅? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任缠犀,我火速辦了婚禮,結果婚禮上聪舒,老公的妹妹穿的比我還像新娘辨液。我一直安慰自己,他們只是感情好过椎,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布室梅。 她就那樣靜靜地躺著戏仓,像睡著了一般疚宇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赏殃,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天敷待,我揣著相機與錄音,去河邊找鬼仁热。 笑死榜揖,一個胖子當著我的面吹牛,可吹牛的內容都是我干的抗蠢。 我是一名探鬼主播举哟,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼迅矛!你這毒婦竟也來了妨猩?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤秽褒,失蹤者是張志新(化名)和其女友劉穎壶硅,沒想到半個月后威兜,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡庐椒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年椒舵,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片约谈。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡笔宿,死狀恐怖,靈堂內的尸體忽然破棺而出棱诱,到底是詐尸還是另有隱情措伐,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布军俊,位于F島的核電站侥加,受9級特大地震影響,放射性物質發(fā)生泄漏粪躬。R本人自食惡果不足惜担败,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望镰官。 院中可真熱鬧提前,春花似錦、人聲如沸泳唠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笨腥。三九已至拓哺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間脖母,已是汗流浹背士鸥。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谆级,地道東北人烤礁。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像肥照,于是被迫代替她去往敵國和親脚仔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內容