??InnoDB支持B+樹索引、全文索引、哈希索引三種索引方式。
B+樹的創(chuàng)建和刪除操作
??B+樹的B是平衡(Balance)的意思。
??B+ 樹索引并不能找到一個(gè)給定鍵值的具體行。 B+ 樹索引能找到的只是被查找數(shù)據(jù)行所在的頁。然后數(shù)據(jù)庫通過把頁讀入到內(nèi)存,再在內(nèi)存中進(jìn)行查找,最后得到要查找的數(shù)據(jù)。
??在數(shù)據(jù)庫中,B+樹的高度一般都在2~4層,也就是說查找某一鍵值的行記錄時(shí),最多只需要2到4次IO。


創(chuàng)建和刪除索引
??索引的創(chuàng)建和刪除可以通過兩種方法,一種是alter table ,另一種是create /drop index。用戶可以設(shè)置對整個(gè)列的數(shù)據(jù)進(jìn)行索引,也可以只索引一個(gè)列的開頭部分?jǐn)?shù)據(jù)。
alter table tbl_name
| add {index|key} {index_name}
{index_type} (index_col_name,...) [index_option]...
alter table tbl_name
drop primary key
|drop {index|key} index_name
create [unique] index index_name
[index_type]
on tbl_name(index_col_name,...)
drop index index_name on tbl_name;
show index命令和Cardinality值
查看表中索引的信息
show index from table_name
??show index from table_name命令輸出中,有一個(gè)Cardinality值,表示索引中唯一值的估計(jì)值,這個(gè)值不是實(shí)時(shí)的,可以使用命令analyze table進(jìn)行實(shí)時(shí)更新,該值越大越好,應(yīng)該盡可能接近表的行數(shù),對于性別、地區(qū)這些值,一般Cardinality都比較小,不建議建立索引。
??在 InnoDB存儲(chǔ)引擎中, Cardinality統(tǒng)計(jì)信息的更新發(fā)生在兩個(gè)操作中: INSERT和 UPDATE。根據(jù)前面的敘述,不可能在每次發(fā)生 INSERT和 UPDATE時(shí)就去更新Cardinality信息,這樣會(huì)增加數(shù)據(jù)庫系統(tǒng)的負(fù)荷,同時(shí)對于大表的統(tǒng)計(jì),時(shí)間上也不允許數(shù)據(jù)庫這樣去操作。因此, InnoDB存儲(chǔ)引擎內(nèi)部對更新 Cardinality信息的策略為:
- 表中116的數(shù)據(jù)已發(fā)生過變化
- stat_modified_counter>2000000000
??第一種策略為自從上次統(tǒng)計(jì) Cardinality信息后,表中1/16的數(shù)據(jù)已經(jīng)發(fā)生過變化,這時(shí)需要更新 Cardinality信息。第二種情況考慮的是,如果對表中某一行數(shù)據(jù)頻繁地進(jìn)行更新操作,這時(shí)表中的數(shù)據(jù)實(shí)際并沒有增加,實(shí)際發(fā)生變化的還是這一行數(shù)據(jù),則第一種更新策略就無法適用這這種情況。故在 InnoDB存儲(chǔ)引擎內(nèi)部有一個(gè)計(jì)數(shù)器stat_modified_counter,用來表示發(fā)生變化的次數(shù),當(dāng) stat_modified_counter大于2000000000時(shí),則同樣需要更新 Cardinality信息。
覆蓋索引
??即從輔助索引中就可以得到查詢的記錄, 而不需要查詢聚集索引中的記錄。 使用覆蓋索引的一個(gè)好處是輔助索引不包含整行記錄的所有信息, 故其大小要遠(yuǎn)小于聚集索引, 因此可以減少大量的 IO 操作。
??對于InnoDB存儲(chǔ)引擎的輔助索引而言,由于其包含了主鍵信息,因此其葉子節(jié)點(diǎn)存放的數(shù)據(jù)為(primary key1,priamey key2,…,key1,key2,…)。例如,下面語句都可僅使用一次輔助聯(lián)合索引來完成查詢:
SELECT key2 FROM table WHERE key1=xxx;
SELECT primary key2,key2 FROM table key1=xxx;
SELECT primary key1,key2 FROM table key1=xxx;
SELECT primary key1,primary key2,key2 FROM table key1=xxx;
??有時(shí)進(jìn)行統(tǒng)計(jì)count()操作時(shí),因?yàn)楦采w索引樹數(shù)據(jù)量比較小,可以減少IO操作,因此InnoDB會(huì)選擇覆蓋索引。
哈希索引
??InnoDB存儲(chǔ)引擎支持的哈希索引是自適應(yīng)的,InnoDB存儲(chǔ)引擎會(huì)根據(jù)表的使用情況自動(dòng)為表生成哈希索引,不能人為干預(yù)是否在一張表中生成哈希索引。
??InnoDB存儲(chǔ)引擎使用哈希算法來對字典進(jìn)行查找,其沖突機(jī)制采用鏈表方式,哈希函數(shù)采用除法散列方式。對于緩沖池頁的哈希表來說,在緩沖池中的Page頁都有一個(gè)chain指針。它指向相同哈希函數(shù)值的頁。而對于除法散列,m的取值略大于2倍的緩沖池頁數(shù)量的質(zhì)數(shù)。例如:當(dāng)前參數(shù)innodb_buffer_pool_size的大小為10M,則共有640個(gè)16kb的頁。對于緩沖池頁內(nèi)存的哈希表來說,需要分配640*2=1280個(gè)槽,但是由于1280不是質(zhì)數(shù),需要取比1280略大的一個(gè)質(zhì)數(shù),應(yīng)該是1399,所以在啟動(dòng)時(shí)會(huì)分配1399個(gè)槽的哈希表,用來哈希查詢所在緩沖池中的頁
??那么在InnoDB存儲(chǔ)引擎的緩沖池對于其中的頁是怎么進(jìn)行查找的呢?上面只是給出了一般的算法,怎么將查找的頁轉(zhuǎn)換成自然數(shù)呢?
??其實(shí)很簡單,InnoDB存儲(chǔ)引擎的表空間都有一個(gè)space_id,用戶所要查找的應(yīng)該是某個(gè)表空間某個(gè)連續(xù)16KB的頁,即偏移量offset,InnoDB存儲(chǔ)引擎將space_id左移20位,然后加上這個(gè)space_id和offset,即關(guān)鍵字K=space_id<<20+space_id+offset,然后通過除法散列到各個(gè)槽中。
自適應(yīng)哈希索引
??innodb存儲(chǔ)引擎有一個(gè)特殊的功能叫自適應(yīng)哈希索引(adaptive hash index),當(dāng)innodb注意到某些索引值被使用的非常頻繁時(shí),它會(huì)在內(nèi)存中基于B+樹索引上再創(chuàng)建一個(gè)哈希索引。這就讓B+樹索引也具有一些哈希索引的優(yōu)點(diǎn),比如快速的哈希查找。這是一個(gè)完全自動(dòng),內(nèi)部的行為,用戶無法控制或配置。
全文索引
??在InnoDB中,全文索引使用full inverted index實(shí)現(xiàn)。

