MySQL 之 InnoDB
1.索引數據結構選擇
索引是爲了提高數據查詢的效率,提高讀寫的數據結構有很多,常見的數據結構有:哈希表,有序數組和平衡二叉查找數。而MySQL的InnoDB爲什麼要選擇B+樹呢?
- 哈希表:插入單個數據時間複雜度爲O(1),查找和刪除時間複雜度跟鏈表的長度成正比,鏈表長爲k時時間複雜度爲O(k)。哈希表中數據是無序的不支持範圍查找,適合於等值查找。
- 有序數組: 通過二分法查找數據時間複雜度爲O(logN),等值和範圍查詢效率很高,但是新增和刪除每次都要移動大量的數據,時間複雜度就變爲了O(n),成本太高。有序數組適合於靜態數據索引查找。
- 平衡二叉查找樹: 平衡二叉查找樹的查詢複雜度爲O(logN),插入和刪除時間複雜度爲O(logN)效率也很高,中序遍歷後也支持範圍查找。
1.1.InnoDB爲什麼選擇B+樹
既然平衡二叉樹這麼高效了爲什麼還要用B+樹作爲MySQL索引的存儲數據結構了。當有數據有100W時,樹高20,一次查詢就需要訪問20個數據塊,從磁盤隨機讀一個數據塊大概需要10ms左右,而內存中讀取數據是納秒級別,在磁盤上讀取20個數據塊所消耗的時間就不能接受了。能不能減少數據塊次數的讀取就成爲關鍵了。
這時候N叉樹就出現了,當N=100時1億個數據樹高就只有3了,查找一次數據最多隻有3次磁盤操作,操作磁盤次數減少,查找效率也就提高了。B+樹其實就是一個父節點有N個子節點既然N叉樹的一種。
1.2.N的取值
在操作系統中讀取磁盤中的數據是按頁讀取,如果讀取的數據小大超過一頁就會出發多次IO操作。在選擇N大小時,儘量讓每個節點的大小等於一個頁的大小。影響N的大小是由頁大小和索引數據大小所決定,如一個也大小爲4KB,索引數據爲整型時,整型數據大小爲4個字節,則N大小爲1024。
2.InnoDB常見索引
InnoDB中的表都是根據主鍵順序按索引的形式存儲,這種存儲方式的表稱爲索引組織表,InnoDB是使用的B+樹作爲索引模型,其數據都存放在葉子節點,父節點存儲着索引值。
-
主鍵索引
主鍵索引是將正行數據都放在葉子節點,MySql中主鍵索引也稱聚簇索引
-
非主鍵索引
非主鍵索引的葉子節點存儲的是主鍵的值,非主鍵索引也被稱之爲二級索引
,其中常見的非主鍵索引包括普通索引
,覆蓋索引
等
2.1.主鍵索引與非主鍵索引的區別
- 主鍵索引葉子節點存儲整行數據,非主鍵索引葉子節點存儲主鍵值
- 主鍵索引只搜索主鍵的B+索引樹,只需要搜索一次。非主鍵索引先搜索自己的索引樹得到主鍵之後再去回查主鍵索引,這個過程叫做回表,非主鍵索引需要進行兩次搜索。
2.2.主鍵索引使用場景
B+樹作爲一個動態數據結構的樹爲了維護索引的有序性,在插入或刪除節點時都要做一些必要的維護,當數據頁寫滿時需要頁分裂,當數據頁利用率不足時需要頁合併。
2.2.1.主鍵自增長
爲什麼主鍵要定義爲自增長,當主鍵定義爲自增長時每次插入一條數據,新增數據ID爲系統中最大的ID+1,這樣數據就能以遞增的方式插入,每次新增都是增加操作,則不會造成葉子節點頁分裂的場景。
當業務字段作爲主鍵時,業務字段不能保證有序數據隨機寫入,從而會造成頁分頁。
主鍵數據長度越小,普通索引所佔空間就越小,主鍵自增長主鍵的數據類型爲整型只佔4個字節
2.2.2.業務字段作爲主鍵
業務字段保證數據唯一
只存在一個索引
典型的場景就是KV場景
2.3.非主鍵索引使用場景
2.3.1.覆蓋索引
聯合索引是多個字段組成的索引,當查詢的字段都在索引列中時就可以直接返回,不需要再次回表查詢,從而減少一次查詢,這個索引稱之爲覆蓋索引
。
覆蓋索引可以減少樹的搜索次數提高性能,可以作爲一種優化方式,選擇場景爲:
- 當要查詢的字段都可以作爲索引,則使用覆蓋索引
- 如果通過調整索引字段順序,可以少維護一個索引,則優先採用這個順序作爲聯合索引的順序,聯合索引遵循最左匹配原則。
2.3.2.索引下推
當一個表數據爲:
ID | name | age |
---|---|---|
id1 | 張三 | 10 |
id2 | 張四 | 20 |
id3 | 張五 | 10 |
id4 | 李六 | 30 |
name和age爲聯合索引。
查詢語句爲:
select * from user where name like '張%' and age=10;
MySQL在5.6之後引入索引下推,上面SQL執行流程爲:
- 聯合索引根據name查詢出id1,id2,id3三條記錄
age=10
條件直接在聯合索引上錄刷選處理只發送id1,id3兩條記錄。- 將id1,id3發送到主鍵索引查詢
根據上述流程來看,索引下推在查詢第一顆索引樹時就做了過濾減少回表的數據量查詢。也可以作爲一種優化方式。
參考文獻
- 極客時間《MySQL實戰45講》