MySQL中90%的慢Sql都可以通過索引來得到優化,爲什麼索引可以使Sql變的更快,我們需要先了解下MySQL InnoDB都有哪些索引。
按規則分類:
Hash索引 |
Memory引擎默認 |
USING HASH |
BTREE索引 |
InnoDB引擎默認B+Tree |
USING BTREE |
按類型分類:
主鍵 |
也叫聚集索引,不允許有Null值 |
唯一索引 |
同主鍵,但允許有Null值 |
二級索引 |
輔助索引 |
全文索引 |
MySQL5.6以後才支持,且只能是char、varchar,text字符類型纔可以創建全文索引 |
複合索引 |
多列聯合的索引,可以是主鍵,也可以是輔助索引 |
數據結構:
不管哪種索引,都是一種數據結構。
哈希表 |
字段值通過Hash算法得出的Hash碼,Hash索引中存儲的即Hash碼 |
二叉樹 |
每個節點包含左右指針、鍵值、存儲地址,左子樹的鍵值小於根的鍵值,右子樹的鍵值大於根的鍵值 |
平衡二叉樹 |
每個節點包含左右指針、鍵值、存儲地址,左子樹的鍵值小於根的鍵值,右子樹的鍵值大於根的鍵值,兩個子樹的高度最大差爲1 |
BTree |
非葉子節點也存儲數據,無雙向鏈指針 |
B+Tree |
只有葉子節點存儲數據,有雙向鏈指針 |
哈希表:
哈希索引就是採用一定的哈希算法,把鍵值換算成新的哈希值,同時在哈希表中保存指向每個數據行的指針。檢索時不需要類似B+Tree那樣從根節點到葉子節點逐級查找,只需一次哈希算法即可定位到相應的位置,速度非常快。但優勢只適用於鍵值唯一的等值查詢。
二叉樹與平衡二叉樹:
二叉樹:可以任意地構造,高度越大效率越低,以下6個值平均查找次數爲(1+2+3+4+5+5)/ 6 = 3.3 次IO。
平衡二叉樹:平衡二叉樹簡稱平衡樹,是由Adelson-Velskii和Landis於1962年首先提出的,所以又稱爲AVL樹。在符合二叉樹的條件下,還滿足任何節點的兩個子樹的高度最大差爲1,以下6個值平均查找次數(1+2+2+3+3+3)/ 6 = 2.3 次IO。
缺點:
大量刪除、新增會導致頻繁旋轉;
實際運用較少,主要用於數據結構研究。
BTree:
BTree是爲磁盤存儲而專門設計的一類平衡搜索樹,文件系統和數據庫系統一般都採用BTree的數據結構,主要爲提升排序和檢索的效率。
由於BTree的所有節點都存儲數據,這就限制了BTree節點擁有孩子節點個數,如果數據量特別大,會導致樹的高度變高,IO就會增多。
模擬查找關鍵字29的過程:
-
根據根節點找到磁盤塊1,讀入內存。【磁盤I/O操作第1次】
-
比較關鍵字29在區間(17,35),找到磁盤塊1的指針P2。
-
根據P2指針找到磁盤塊3,讀入內存。【磁盤I/O操作第2次】
-
比較關鍵字29在區間(26,30),找到磁盤塊3的指針P2。
-
根據P2指針找到磁盤塊8,讀入內存。【磁盤I/O操作第3次】
-
在磁盤塊8中的關鍵字列表中找到關鍵字29。
分析上面過程,發現需要3次磁盤I/O操作,和3次內存。
但如果我們想進行範圍查找,查詢10~79之間的數據,就需要從跟節點一個一個往下查,範圍跨度越大,則磁盤IO的次數就越多,性能越差。因此在BTree的基礎上就有了B+Tree。
B+Tree:
B+Tree是在BTree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。
B+Tree相對於BTree有幾點不同:
-
非葉子節點只存儲鍵值信息。
-
所有葉子節點之間都有一個雙向鏈指針。
-
數據記錄都存放在葉子節點中。
這樣索引樹不用太高,就能滿足需要對數據的檢索需求,使查詢更快速,例如:
定義一棵B+Tree,高度h = 3;
我們知道MySQL InnoDB默認數據頁大小爲16k;
MySQL root@[mysql]>show global status like 'Innodb_page_size';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| Innodb_page_size | 16384 |
+------------------+-------+
假設字符集爲utf8,在一個int字符類型的字段加索引(int固定佔4個字節);
一個Page除去頁號、頁類型等10個字節(如下圖);
非葉子節點存儲鍵值(扇出係數) = 16384 / (4+10) = 1170 個Key;
所以在高度h=3時,索引裏檢索的key爲:1170^3 ≈ 16億,即只需要3次IO就能檢索16億的key。
如果是varchar等其他字符類型,佔用Page字節較大,非葉子節點存儲鍵值會減少,相應可檢索的key也減少,樹高度就有可能會升高,IO會就多一次,從而導致相對變慢。一般2~4層高度大部分已經夠用了。
B+Tree主鍵索引:
InnoDB中主鍵索引的葉子節點的數據區域存儲的是數據記錄,輔助索引存儲的是主鍵值。
B+Tree輔助索引:
Innodb中的主鍵索引和實際數據時綁定在一起的,也就是說Innodb的一個表一定要有主鍵索引,如果一個表沒有手動建立主鍵索引,Innodb會查看有沒有唯一索引,如果有則選用唯一索引作爲主鍵索引,如果連唯一索引也沒有,則會默認建立一個隱藏的主鍵索引(用戶不可見)。另外,Innodb的主鍵索引要比MyISAM的主鍵索引查詢效率要高(少一次磁盤IO),並且比輔助索引也要高很多。
所以,我們在使用Innodb作爲存儲引擎時,我們最好:
-
每個表都創建主鍵索引
-
最好是int型作爲主鍵
-
儘量根據主鍵查詢