1. InnoDB中用到的索引是B+樹,回顧一下B+樹的知識。
2. 聚集索引
每張InnoDB表都會有一個聚集索引用于指定行數據存放的順序。默認情況下,InnoDB以表的主鍵作為聚集索引,即該表按照主鍵的大小順序進行存儲的。而聚集索引就是以主鍵構造的一顆B+樹,且葉子節點就是行數據本身。
InnoDB聚集索引的選取:
如果表有主鍵則主鍵就是聚集索引,如果沒有則選取第一個UNIQUE索引且索引對應的行是NOT NULL的,如果還沒有,則系統自動生成。
1. 聚集索引的特點:
- 由于一張表的排列順序只有一種,所以一張表也最多只能有一個聚集索引
- 我們創建表時,無法手動指定聚集索引的。
2. 聚集索引的優點
- 由于葉子節點存放的就是行數據本身,所以查找只需要一次遍歷B+樹就可以找到
- 對聚集索引字段的排序和范圍查找很快
- 排序:因為聚集索引已經是排好序的,所以無需再進行排序操作。
- 范圍:我們只需要找到范圍的兩端,且由于葉子節點是一個雙向鏈表,且是數據本身,所以兩端葉子之間的葉子節點就是結果。
3. 非聚集索引
除了聚集索引的索引都叫非聚集索引。
非聚集索引和聚集索引的區別就是葉子節點存放的數據。且非聚集索引顯然一張表可以有多個的。
- 聚集索引葉子節點存放的是行數據本身。
- 非聚集索引葉子節點存放的是聚集索引的值。
所以對非聚集索引的查找[通常情況下]至少要經過兩次B+樹的遍歷。且范圍查找時,找到所有符合條件的聚集索引值之后,需要依次對每個聚集索引值找到對應的數據。
MyISAM引擎表不存在聚集索引,所有的索引的葉子節點存放的都是行數據的地址,即每次查找通過B+樹找到數據的地址,然后再根據地址找到具體的數據。
4. 聯合索引
如果有一個聯合索引(a,b),則就會建一個這樣的組合樹,樹的節點每個“值”都是一個數值對,而且按照a的大小順序排的,當a相等時,才會根據b的大小排。如圖。
所以(a,b)索引時,可以單獨查a也會走索引。而如果單獨查b則不會走索引。
- 聯合索引的第二個好處:
已經對第二個鍵做好了排序,比如:
select * from t where a = 5 order by b
其實order by b這步是不需要進行任何額外開銷的,因為聯合索引已經對b做好了排序了,所以直接取a = 5就可以了。
5. 覆蓋索引
InnoDB是支持覆蓋索引的,即從非聚集索引中就可以得到想要的結果,而不需進行回聚集索引查詢。
這樣的情況有兩種:
1. 根據非聚集索引的條件查詢聚集索引對應列的值
例如:加入a是聚集索引,b是非聚集索引
select a from t where b = 2;
我們知道非聚集索引葉子節點存的就是聚集索引的值,所以這個查詢只需進行一次B+樹搜索就可以了。
2. 某些統計問題
因為非聚集索引存的只是聚集索引的值,而聚集索引存的是整個行數據,所以非聚集索引的大小要遠遠小于聚集索引,小就意味著更少的IO。所以如果可以通過非聚集索引完成的事,就不要使用聚集索引。
例如:假設t有主鍵a,和非聚集索引b
select count(*) from t;
這條語句使用的就是b,因為b更小更高效。
覆蓋索引有個特點:
- 使用explain進行執行過程分析時,extra字段是using index
- 一般情況下,聯合索引(a,b),根據b的查詢不會用到這個聯合索引,但如果查詢的是count就可能會用到。
select count(*) from t where b = 2;
用到這個索引的原因是因為非聚集索引很小,查詢的效果快。
6. 索引提示
當InnoDB最終使用的index并不是最優的時(這種情況幾乎不會出現),我們可以給它一些提示,建議它用某個索引。
select * from t user index(ix_a) where a = 1;
注意這里只是建議它使用,最終使用的索引還是由InnoDB自己決定。
對之對應的還有force index,即強制這條查詢語句使用某個索引。
select * from t force index(ix_a) where a = 1;