在上一篇文章中,介紹了InnoDB索引的數(shù)據(jù)結(jié)構(gòu)模型,現(xiàn)在聊聊跟MySQL索引有關(guān)的概念。
在下面這個表 T 中,如果我執(zhí)行 select * from T where k between 3 and 5,需要執(zhí)行幾次樹的搜索操作,會掃描多少行?下面是這個表的初始化語句。
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');

現(xiàn)在我們看一下這條sql的執(zhí)行流程:
1、在k索引樹上找到k = 3的記錄,獲取ID=300;
2、再到ID索引樹上找到ID=300對應(yīng)的R3;
3、在k索引樹上取下一個值k = 5的記錄,獲取ID=500;
4、再到ID索引樹上找到ID=500對應(yīng)的R4;
5、在k索引樹上取下一個值k = 6不滿足,循環(huán)結(jié)束。
在這個過程中,回到主鍵索引樹搜索的過程,我們稱為回表。
在這個例子中,由于查詢結(jié)果所需要的數(shù)據(jù)只在主鍵索引上有,所以不得不回表。那么,有沒有可能經(jīng)過索引優(yōu)化,避免回表過程呢?
覆蓋索引
如果執(zhí)行的語句是 select ID from T where k between 3 and 5,這時只需要查 ID 的值,而 ID 的值已經(jīng)在 k 索引樹上了,因此可以直接提供查詢結(jié)果,不需要回表。也就是說,在這個查詢里面,索引 k 已經(jīng)“覆蓋了”我們的查詢需求,我們稱為覆蓋索引。由于覆蓋索引可以減少樹的搜索次數(shù),顯著提升查詢性能,所以使用覆蓋索引是一個常用的性能優(yōu)化手段。
最左前綴原則
B+ 樹這種索引結(jié)構(gòu),可以利用索引的“最左前綴”,來定位記錄。即如果查詢的時候查詢條件精確匹配索引的左邊連續(xù)一列或幾列,直到遇到范圍查詢(>、<、between、like)就停止匹配。
索引下推
我們還是以聯(lián)合索引(name,age)為例。如果現(xiàn)在有一個需求:檢索出表中“名字第一個字是張,而且年齡是 10 歲的所有男孩”。那么,SQL 語句是這么寫的:
select * from user where name like '張%' and age=10 and ismale=1;
你已經(jīng)知道了前綴索引規(guī)則,所以這個語句在搜索索引樹的時候,只能用 “張”,找到第一個滿足條件的記錄 ID3。當(dāng)然,這還不錯,總比全表掃描要好。
在 MySQL 5.6 之前,只能從 ID3 開始一個個回表。到主鍵索引上找出數(shù)據(jù)行,再對比字段值。而 MySQL 5.6 引入的索引下推優(yōu)化(index condition pushdown), 可以在索引遍歷過程中,對索引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數(shù)。