低年級(jí)時(shí)期的赫敏 真的好漂亮
InnoDB中的索引模型
在InnoDB中表都是跟隨主鍵順序,以索引的形式存放的揪阶。這種存儲(chǔ)方式的表稱為索引組織表昌抠。
InnoDB采用了B+tree索引模型,所以數(shù)據(jù)都是存儲(chǔ)在B+??中的
每一個(gè)索引在InnoDB中對(duì)應(yīng)一顆 B+ ??
主鍵索引的子葉節(jié)點(diǎn)存的是整行數(shù)據(jù)遣钳。在InnoDB里,主鍵索引也叫聚簇索引
非主鍵索引的子葉節(jié)點(diǎn)內(nèi)容是主鍵的值。在InnoDB里蕴茴,非主鍵索引也叫二級(jí)索引劝评。
基于主鍵索引和普通索引查詢的區(qū)別?
mysql> create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;
select * from T where id=500; 對(duì)于主鍵查詢方式倦淀,只需要搜索ID這顆B+??
select * from T where k=5; 普通索引查詢方式蒋畜,首先搜索k索引??,獲得對(duì)應(yīng)的ID值撞叽,在用Id在 id索引??在搜索一次姻成,這個(gè)過(guò)程叫做回表。
so愿棋,赫敏溫馨提醒 :盡量使用主鍵索引咯~~~
索引的維護(hù)
B+??為了維護(hù)索引的有序性科展,在插入新值的時(shí)候就需要做必要的維護(hù),以上面這個(gè)圖為例糠雨,如果插入新的行 ID 值為 700才睹,,則只需要在 R5 的記錄后面插入一個(gè)新記錄甘邀。如果新插入的 ID 值為 400琅攘,就相對(duì)麻煩了需要邏輯上挪動(dòng)后面的數(shù)據(jù),空出位置松邪。
而更糟的情況是坞琴,如果 R5 所在的數(shù)據(jù)頁(yè)已經(jīng)滿了,根據(jù) B+ 樹的算法逗抑,這時(shí)候需要申請(qǐng)一個(gè)新的數(shù)據(jù)頁(yè)剧辐,然后挪動(dòng)部分?jǐn)?shù)據(jù)過(guò)去。這個(gè)過(guò)程稱為頁(yè)分裂锋八。在這種情況下浙于,性能自然會(huì)受影響。
除了性能外挟纱,頁(yè)分裂操作還影響數(shù)據(jù)頁(yè)的利用率羞酗。原本放在一個(gè)頁(yè)的數(shù)據(jù),現(xiàn)在分到兩個(gè)頁(yè)中紊服,整體空間利用率降低大約 50%檀轨。
當(dāng)然有分裂就有合并。當(dāng)相鄰兩個(gè)頁(yè)由于刪除了數(shù)據(jù)欺嗤,利用率很低之后参萄,會(huì)將數(shù)據(jù)頁(yè)做合并。合并的過(guò)程煎饼,可以認(rèn)為是分裂過(guò)程的逆過(guò)程讹挎。
mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;
insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
如果我執(zhí)行 select * from T where k between 3 and 5,需要執(zhí)行幾次樹的搜索操作,會(huì)掃描多少行筒溃?
1马篮、在 k 索引樹上找到 k=3 的記錄,取得 ID = 300...
2怜奖、再到 ID 索引樹查到 ID=300 對(duì)應(yīng)的 R3浑测;
3、在 k 索引樹取下一個(gè)值 k=5歪玲,取得 ID=500迁央;
4、再回到 ID 索引樹查到 ID=500 對(duì)應(yīng)的 R4滥崩;
5岖圈、在 k 索引樹取下一個(gè)值 k=6,不滿足條件夭委,循環(huán)結(jié)束幅狮。
在這個(gè)過(guò)程中,回到主鍵索引樹搜索的過(guò)程株灸,我們稱為回表崇摄。可以看到慌烧,這個(gè)查詢過(guò)程讀了 k索引樹的 3 條記錄(步驟 1逐抑、3 和 5),回表了兩次(步驟 2 和 4)屹蚊。
索引覆蓋
如果執(zhí)行的語(yǔ)句是 select ID from T where k between 3 and 5厕氨,這時(shí)只需要查 ID 的值,而ID 的值已經(jīng)在 k 索引樹上了汹粤,因此可以直接提供查詢結(jié)果命斧,不需要回表。也就是說(shuō)嘱兼,在這個(gè)查詢里面国葬,索引 k 已經(jīng)“覆蓋了”我們的查詢需求,我們稱為索引覆蓋芹壕。
由于索引覆蓋可以減少索引樹的搜索次數(shù)汇四,顯著提升查詢性能,所以使用覆蓋索引是一個(gè)常用的性能提升手段
最左前綴原則
B+ 樹這種索引結(jié)構(gòu)踢涌,可以利用索引的“最左前綴”通孽,來(lái)定位記錄。
在建立聯(lián)合索引的時(shí)候睁壁,如何安排索引內(nèi)的字段順序背苦。
第一原則是互捌,如果通過(guò)調(diào)整順序,可以少維護(hù)一個(gè)索引行剂,那么這個(gè)順序往往就是需要優(yōu)先考慮采用的疫剃。
還要考慮到空間原則
聯(lián)合索引(name, age)
可以看到硼讽。索引項(xiàng)是按照索引定義里面出現(xiàn)的字段順序排序的。
索引下推
mysql> select * from tuser where name like '張 %' and age=10 and ismale=1;
Mysql5.6 引入索引下推優(yōu)化(index condition pushdown) 牲阁,在索引遍歷過(guò)程中固阁,
對(duì)索引包含的字段先進(jìn)行判斷,直接過(guò)濾掉不符合條件的記錄城菊,減少回表次數(shù)备燃。
鳴謝 林曉斌 發(fā)布在極客時(shí)間上的Mysql45講 格蘭杰用金加隆訂閱的哦~~~