索引是存儲引擎用來快速查找記錄的一種數據結構,按照實現的方式有不一樣的種類,想B-Tree索引,hash索引,空間數據索引和全文索引等。下面主要說一下B-Tree索引和Hash索引。
人們在談論索引的時候若是沒有特別說明,通常指的是B-Tree索引。B-Tree索引是使用B-Tree數據結構來存儲索引的。B-Tree一般意味着全部的值是按照順序存儲的。B-Tree樹有以下幾個特徵:
⑴樹中每一個結點至多有m 棵子樹;
⑵若根結點不是葉子結點,則至少有兩棵子樹;
⑶除根結點以外的全部非終端結點至少有[m/2] 棵子樹;
⑷全部的非終端結點中包含如下信息數據:
(n,A0,K1,A1,K2,…,Kn,An)
其中:Ki(i=1,2,…,n)爲關鍵碼,且Ki<Ki+1,html
Ai 爲指向子樹根結點的指針(i=0,1,…,n),且指針Ai-1 所指子樹中全部結點的關鍵碼均小於Ki (i=1,2,…,n),An 所指子樹中全部結點的關鍵碼均大於Kn.mysql
n 爲關鍵碼的個數。
⑸全部的葉子結點都出如今同一層次上,而且不帶信息(能夠看做是外部結點或查找失敗的結點,實際上這些結點不存在,指向這些結點的指針爲空)。 即全部葉節點具備相同的深度,等於樹高度。
對於B-Tree索引,存儲引擎在查找記錄的時候再也不是經過掃描全表來獲取須要的數據麼人是從索引的根節點進行搜索,根節點的槽中存放了指向子節點的指針,存儲引擎根據這些指針向下查找。最後找到葉子節點。葉子節點比較特殊,他的指針指向的是索引的數據。並且不一樣的存儲引擎實現也不同。在mysql中MyISAM中指針指向的是數據的指針,而在InnoDB中,直接存放的是數據。sql
那麼在什麼狀況下B-Tree可使用索引呢?假設存在一張user表,咱們對(「姓」,「名」,「出生日期」)創建符合索引,那麼在B-Tree的key中就是按照姓,名,出生日期順序存儲的,這樣方便咱們理解下面這些狀況:
1,全值匹配,指的是索引中的全部列進行匹配。好比 where 姓=‘張’ and 名=‘小凡’and 出生年月=‘1990-12-21’;
2,匹配最左前綴。好比查找 姓=‘張’,只能使用第一列。你想若是咱們要名=‘三’,那麼能夠是‘趙三’,‘李三’索引中先根據姓排序,因此名=‘三’的根本沒在一塊兒,沒法使用索引。
3,匹配列前綴 好比查找‘歐%’;
4,匹配範圍值 可使用索引列的第一列。
5,精確匹配某一列,在範圍匹配另一列。
根據B-Tree存儲的特色,很容易知道有一些狀況是沒有辦法使用索引的。好比以下狀況:
1,不是按照索引列最左側開始查找。
2,跳過中介的列。
3,若是某個列採用範圍查找,那麼右側的列都沒有辦法使用索引。
B-Tree索引有一些獨特的好處的,好比在B-Tree樹的key中存放了索引列的值,因此若是咱們只須要查詢索引列的結果就能夠直接使用索引而不須要去查找記錄了。這就是覆蓋索引的優化。
另外,由於B-Tree索引是有序的,因此除了查找以外,索引還能夠用於查詢中的order by 排序。
Hash索引
哈希索引是基於哈希表實現的。只有精確匹配索引全部列的的查詢纔有效。他的實現是存儲殷勤會對每一行數據的索引列計算哈希碼,並將哈希碼和指向該記錄的指針維護起來,對於hash相同的,採用鏈表的方式解決衝突。相似於hashmap。由於索引的結構是十分緊湊的,因此hash索引的查詢很快。
可是hash索引也有他的限制:
1,hash索引只包含了哈希值和行指針,索引不能避免讀取行,不能使用覆蓋索引。
2,hash索引並非按照索引順序存儲的,沒法用於排序。
3,hash索引不支持部分或者區域查找,部分列的hash結果是不一樣的。
在Mysql中InnoDB引擎有一個特殊的功能叫作自適應哈希索引,他會在內存中基於B-Tree索引的基礎上面建立一個哈希索引,這讓B-Tree索引頁具有了一些哈希索引的優勢。
在《高性能的Mysql》這本樹中,做者舉了一個自定義哈希索引的列子。假設咱們在一個表中大量存儲了URL,並且須要根據URL來進行查找。由於URL比較長,這個時候若是咱們使用B-Tree索引來,索引會很是的大。解決的辦法是在列表中增長一個列,用來存放URL的哈希值,能夠經過CRC32對URL進行計算,並存放在列表中,在查找的時候經過CRC32對url進行計算匹配列表中的hash值。
可是這個地方須要注意hash衝突的問題,因此在查詢的時候須要添加url的匹配。
例如:where url_crc=CRC32(「http://www.cnblogs.com/yimixiong/p/7400914.html」) and url=」 http://www.cnblogs.com/yimixiong/p/7400914.html」數據結構