正式講 ICP 之前了,我們先將相關(guān)的概念捋一捋,知道的就當(dāng)回顧,不知道的就當(dāng)了解了,這有助于對(duì) ICP 的理解
建個(gè)示例表 tbl_index
CREATE TABLE tbl_index (
c1 INT,
c2 INT,
c3 CHAR(1),
PRIMARY KEY(c1),
KEY idx_c2 (c2)
);
如果 where 條件的列和 select 的列都在一個(gè)索引中,通過(guò)這個(gè)索引就可以完成查詢,這就叫就叫覆蓋索引;當(dāng)然,覆蓋索引基本針對(duì)的是組合索引(InnoDB 的聚簇索引有點(diǎn)特殊,具體可以看下面的圖)
針對(duì)上面的 tbl_index, select c2 from tbl_index where c2 = 4; 是覆蓋索引查詢,但是這條 SQL 沒(méi)有意義,如果我們?cè)?tbl_index 表上增加索引 index idx_c2_c3 (c2,c3) ,那么 select c3 from tbl_index where c2 = 4; 走覆蓋索引查詢還是很有意義的,那問(wèn)題又來(lái)了,覆蓋索引的意義何在 ? 我們往下看
通過(guò)某個(gè)索引無(wú)法直接完成 SQL 查詢(where 條件的列和 select 的列不全部存在于任何一個(gè)索引中),那么此時(shí)需要獲取完整的數(shù)據(jù)記錄來(lái)完成此次查詢,從索引項(xiàng)記錄到獲取對(duì)應(yīng)的完整數(shù)據(jù)記錄的過(guò)程就叫回表;概念可能說(shuō)的有些抽象,我們結(jié)合 MySQL 來(lái)看看具體什么是回表
InnoDB 的回表
InnoDB 的索引結(jié)構(gòu)有些特殊,非聚簇索引(二級(jí)索引)回表到聚簇索引的過(guò)程類似如下
InnoDB的聚簇索引即數(shù)據(jù),索引和數(shù)據(jù)是存在一起的;那么直接走聚簇索引查詢的 SQL 是不存在回表一說(shuō)的,比如 select* from tbl_index where c1 = 10; ,只有從二級(jí)索引出發(fā),并且二級(jí)索引獨(dú)自完成不了查詢的時(shí)候才會(huì)回表到聚簇索引完成查詢
MyISAM 的回表
有這樣一種說(shuō)法: MyISAM 中的索引都是二級(jí)索引 ,其實(shí)說(shuō)的是聚簇索引和二級(jí)索引的結(jié)構(gòu)基本一致,只是聚簇索引有個(gè)唯一性約束
MyISAM 聚簇索引和二級(jí)索引,以及它們的回表過(guò)程類似如下
MyISAM 的回表過(guò)程指的是根據(jù)葉子節(jié)點(diǎn)中的數(shù)據(jù)記錄的地址來(lái)獲取完整記錄的過(guò)程,無(wú)論是聚簇索引還是二級(jí)索引都可能存在回表的過(guò)程;MyISAM 的回表與 InnoDB 還是有差別的
無(wú)論是 InnoDB 的回表還是 MyISAM 的回表,很有可能會(huì)造成額外的磁盤(pán) IO,這會(huì)嚴(yán)重影響查詢效率,覆蓋索引的目的就是盡量能夠一次完成 SQL 查詢,避免有回表過(guò)程,從而提高效率
如何確認(rèn) MySQL 是進(jìn)行了覆蓋索引查詢,還是進(jìn)行了回表查詢 ?
看 MySQL 的執(zhí)行計(jì)劃,如果 Extra 中只有 using index 則說(shuō)明使用了覆蓋索引查詢,如果 Extra 中出現(xiàn)了 using indexcondition 或 using index & using where 則說(shuō)明進(jìn)行了回表查詢
Index Condition Pushdown,MySQL 5.6 中引入的一種優(yōu)化策略
那么究竟是將什么從哪 Push Down 到哪,優(yōu)化了什么?要弄清楚這 4 個(gè)問(wèn)題,我們需要先弄清楚 where 條件的提取與應(yīng)用,具體可查看:神奇的 SQL 之 WHERE 條件的提取與應(yīng)用
where 條件會(huì)被提取成 3 部分: Index Key,Index Filter,Table Filter ,在 MySQL 5.6 之前,并不區(qū)分 Index Filter 與 Table Filter,統(tǒng)統(tǒng)將 Index First Key 與 Index Last Key 范圍內(nèi)的索引記錄,回表讀取完整記錄,然后返回給 MySQL Server 層進(jìn)行過(guò)濾,而在 MySQL 5.6 之后,Index Filter 與 Table Filter 分離,Index Filter 下降到引擎層(InnoDB和MyISAM)的索引層面進(jìn)行過(guò)濾,減少了回表與返回 MySQL Server 層的記錄交互開(kāi)銷,提高了 SQL 的執(zhí)行效率
假設(shè)我們有表: tbl_icp
create table tbl_icp (a int primary key, b int, c int, d int, e varchar(50));create index idx_bcd on tbl_icp(b, c, d);insert into tbl_icp values (4,3,1,1,'a');insert into tbl_icp values (1,1,1,2,'d');insert into tbl_icp values (8,8,7,8,'h');insert into tbl_icp values (2,2,1,2,'g');insert into tbl_icp values (5,2,2,5,'e');insert into tbl_icp values (3,3,2,1,'c');insert into tbl_icp values (7,4,0,5,'b');insert into tbl_icp values (6,5,2,4,'f');
若沒(méi)有使用 ICP,則 SQL 查詢類似如下
沒(méi)有使用 ICP 時(shí),引擎層會(huì)將滿足 Index Key 范圍限制的所有數(shù)據(jù)記錄(示例中一共 6 條)逐條返回給 Server 層,然后由 server 層應(yīng)用 Index Filter 和 Table Filter (MySQL 5.6 之前不區(qū)分 Index Filter 和 Table Filter),最后將滿足條件的數(shù)據(jù)返回給客戶端;
若使用 ICP,則 SQL 查詢類似如下
使用了 ICP,Server 層會(huì)將 Index Filter 下推到引擎層,引擎層在對(duì) Index First Key 與 Index Last Key 范圍內(nèi)的索引項(xiàng)逐條進(jìn)行過(guò)濾的時(shí)候,會(huì)應(yīng)用上 Index Filter,對(duì)不滿足 Index Filter 條件的索引項(xiàng)直接過(guò)濾掉,無(wú)需回表操作,也無(wú)需返回給 Server 層,從而提供執(zhí)行效率;上圖中的索引項(xiàng): 3 1 1 、 3 2 1 不滿足 Index Filter 中的 d != 1 , 4 0 5 不滿足 c > 0 ,所以這 3 個(gè)索引項(xiàng)無(wú)需進(jìn)行回表操作,也不需要返回給 Server 層
相信到這里,大家對(duì) ICP 的 4 個(gè)問(wèn)題應(yīng)該就比較清楚了
雖說(shuō) ICP 能提高 SQL 執(zhí)行效率,但也不是任何情況下都適用的,它只適用于某些情況
1、當(dāng) SQL 需要全表訪問(wèn)時(shí),ICP 的優(yōu)化策略可用于 range, ref, eq_ref, ref_or_null 類型的數(shù)據(jù)訪問(wèn)方式
2、只適用于 InnoDB 和 MyISAM 兩種存儲(chǔ)引擎
3、在 InnoDB 中,ICP 只適用于二級(jí)索引
ICP 的目的就是為了減少回表導(dǎo)致的磁盤(pán) I/O,而 InnoDB 的聚簇索引的葉子節(jié)點(diǎn)存放的就是完整的數(shù)據(jù)記錄,只要索引數(shù)據(jù)被讀到內(nèi)存了,那么索引項(xiàng)對(duì)應(yīng)的完整數(shù)據(jù)記錄也就讀到內(nèi)存了,那么通過(guò)索引項(xiàng)獲取數(shù)據(jù)記錄的過(guò)程就在內(nèi)存中進(jìn)行了,無(wú)需進(jìn)行磁盤(pán) I/O;也就說(shuō)聚簇索引上應(yīng)用 ICP,不會(huì)減少磁盤(pán) I/O,也就沒(méi)有使用的意義了
4、不支持覆蓋索引
其實(shí)和第 3 點(diǎn)一樣,因?yàn)楦采w索引無(wú)需回表,ICP 也就沒(méi)意義了
5、不支持子查詢條件的下推
6、不支持存儲(chǔ)過(guò)程條件、觸發(fā)器條件的下推
至于 ICP 的優(yōu)化效果,取決于在存儲(chǔ)引擎內(nèi)通過(guò) ICP 篩選掉的數(shù)據(jù)的比例,過(guò)濾掉的數(shù)據(jù)比例大,那就性能提升大,反之則性能提升小
1、索引覆蓋與回表
這兩個(gè)往往是一起來(lái)考慮的,因?yàn)楦采w索引的目的就是減少因回表產(chǎn)生的磁盤(pán) I/O,從而提高執(zhí)行效率
在實(shí)際應(yīng)用中,我們往往也需要考慮盡可能用覆蓋索引來(lái)完成我們的 SQL 查詢
2、ICP的四個(gè)問(wèn)題
將什么從哪 Push Down 到哪,優(yōu)化了什么
將 Index Filter 從 Server 層 Push Down 到了引擎層,減少了因回表產(chǎn)生的磁盤(pán) I/O,也減少了與 Server 層的交互,提高了 SQL 執(zhí)行效率
3、疑問(wèn)點(diǎn)
為什么這么明顯的優(yōu)化策略到 MySQL 5.6 才引入,個(gè)人感覺(jué)很容易就能考慮到呀,MySQL 的開(kāi)發(fā)者們是腫么肥事 ?
來(lái)源:https://www.icode9.com/content-4-654201.html聯(lián)系客服