了解一下MySQL中的回表查詢(xún)與索引覆蓋泌豆。
回表查詢(xún)
要說(shuō)回表查詢(xún),先要從InnoDB的索引實(shí)現(xiàn)說(shuō)起丧凤。InnoDB有兩大類(lèi)索引利虫,一類(lèi)是聚集索引(Clustered Index),一類(lèi)是普通索引(Secondary Index)献宫。
InnoDB的聚集索引
InnoDB聚集索引的葉子節(jié)點(diǎn)存儲(chǔ)行記錄钥平,因此InnoDB必須要有且只有一個(gè)聚集索引。
1.如果表定義了PK(Primary Key,主鍵)涉瘾,那么PK就是聚集索引知态。
2.如果表沒(méi)有定義PK,則第一個(gè)NOT NULL UNIQUE的列就是聚集索引立叛。
3.否則InnoDB會(huì)另外創(chuàng)建一個(gè)隱藏的ROWID作為聚集索引负敏。
這種機(jī)制使得基于PK的查詢(xún)速度非常快秘蛇,因?yàn)橹苯佣ㄎ坏男杏涗洝?/p>
InnoDB的普通索引
InnoDB普通索引的葉子節(jié)點(diǎn)存儲(chǔ)主鍵值(MyISAM則是存儲(chǔ)的行記錄頭指針)其做。
什么是回表查詢(xún)
假設(shè)有個(gè)t表(id PK, name KEY, sex, flag),這里的id是聚集索引赁还,name則是普通索引妖泄。
表中有四條記錄:
idnamesexflag
1sjmA
3zsmA
5lsmA
9wwfB
聚集索引的B+樹(shù)索引(id是PK,葉子節(jié)點(diǎn)存儲(chǔ)行記錄):
普通索引的B+樹(shù)索引(name是KEY艘策,葉子節(jié)點(diǎn)存儲(chǔ)PK值蹈胡,即id):
普通索引因?yàn)闊o(wú)法直接定位行記錄,其查詢(xún)過(guò)程在通常情況下是需要掃描兩遍索引樹(shù)的朋蔫。
select*fromtwherename='lisi';
這里的執(zhí)行過(guò)程是這樣的:
粉紅色的路徑需要掃描兩遍索引樹(shù)罚渐,第一遍先通過(guò)普通索引定位到主鍵值id=5,然后第二遍再通過(guò)聚集索引定位到具體行記錄驯妄。這就是所謂的回表查詢(xún)荷并,即先定位主鍵值,再根據(jù)主鍵值定位行記錄富玷,性能相對(duì)于只掃描一遍聚集索引樹(shù)的性能要低一些璧坟。
索引覆蓋
索引覆蓋是一種避免回表查詢(xún)的優(yōu)化策略。具體的做法就是將要查詢(xún)的數(shù)據(jù)作為索引列建立普通索引(可以是單列索引赎懦,也可以一個(gè)索引語(yǔ)句定義所有要查詢(xún)的列雀鹃,即聯(lián)合索引),這樣的話(huà)就可以直接返回索引中的的數(shù)據(jù)励两,不需要再通過(guò)聚集索引去定位行記錄黎茎,避免了回表的情況發(fā)生。
覆蓋索引的定義與注意事項(xiàng)
如果一個(gè)索引覆蓋(包含)了所有需要查詢(xún)的字段的值当悔,這個(gè)索引就是覆蓋索引傅瞻。因?yàn)樗饕幸呀?jīng)包含了要查詢(xún)的字段的值,因此查詢(xún)的時(shí)候直接返回索引中的字段值就可以了盲憎,不需要再到表中查詢(xún)嗅骄,避免了對(duì)主鍵索引的二次查詢(xún),也就提高了查詢(xún)的效率饼疙。
要注意的是溺森,不是所有類(lèi)型的索引都可以成為覆蓋索引的。因?yàn)楦采w索引必須要存儲(chǔ)索引的列值,而哈希索引屏积、空間索引和全文索引等都不存儲(chǔ)索引列值医窿,索引MySQL只能使用B-Tree索引做覆蓋索引。
另外炊林,當(dāng)發(fā)起一個(gè)被索引覆蓋的查詢(xún)(索引覆蓋查詢(xún))時(shí)姥卢,在explain(執(zhí)行計(jì)劃)的Extra列可以看到【Using Index】的信息。
覆蓋索引的優(yōu)點(diǎn)
1.索引條目通常遠(yuǎn)小于數(shù)據(jù)行的大小渣聚,因?yàn)楦采w索引只需要讀取索引独榴,極大地減少了數(shù)據(jù)的訪(fǎng)問(wèn)量。
2.索引是按照列值順序存儲(chǔ)的奕枝,對(duì)于IO密集的范圍查找會(huì)比隨機(jī)從磁盤(pán)讀取每一行數(shù)據(jù)的IO小很多括眠。
3.一些存儲(chǔ)引擎比如MyISAM在內(nèi)存中只緩存索引,數(shù)據(jù)則依賴(lài)操作系統(tǒng)來(lái)緩存倍权,因此要訪(fǎng)問(wèn)數(shù)據(jù)的話(huà)需要一次系統(tǒng)調(diào)用,使用覆蓋索引則避免了這一點(diǎn)捞烟。
4.由于InnoDB的聚簇索引薄声,覆蓋索引對(duì)InnoDB引擎下的數(shù)據(jù)庫(kù)表特別有用。因?yàn)镮nnoDB的二級(jí)索引在葉子節(jié)點(diǎn)中保存了行的主鍵值题画,如果二級(jí)索引能夠覆蓋查詢(xún)默辨,就避免了對(duì)主鍵索引的二次查詢(xún)。