MySQL索引詳解
一. 索引簡介
- 索引:幫助MySQL高效查詢數據的一種有序的數據結構。
-
如果沒有索引,查詢某行數據,只能進行全表掃描。這時,需要頻繁地進行磁盤IO,性能很差。
-
索引一般是一個key-value結構,key是索引值
對於聚集索引(InnoDB),value是該行的所有數據
對於非聚集索引(MyISAM),value是該行所在的磁盤塊的指針
二. 常用的索引數據結構
-
二叉樹(非平衡二叉樹)
弊端:無法保證平衡性。極端情況下,可能退化成鏈表。
-
紅黑樹(平衡二叉樹)
- 優勢:平衡樹,不會退化成鏈表,查詢效率有一定提升。
- 弊端:當數據量較大時,樹的高度不可控,導致磁盤IO次數較多,效率下降。
- 優化思路:讓一個樹的節點存儲多個索引元素,有效降低樹的高度。
-
B樹
-
特性:
- 樹的每個節點,存儲多個索引元素,同時存儲索引對應的數據
- 葉節點具有相同的深度,葉節點的指針爲空
- 所有索引元素不重複
- 節點中的數據索引從左到右遞增排列
-
弊端:
-
樹的所有節點(包括葉子節點和非葉子節點)都同時存儲索引和數據,導致每個索引元素所佔空間較大。當樹的節點空間一定時,每個節點存保存的索引元素數量就較少,最終導致樹的高度較高。
-
樹的每個節點的大小是固定的,一般爲一頁(Page)16KB。可通過命令查看:
show global status like ‘Innodb_page_size’;
-
-
優化思路:儘可能減少每個索引元素所佔的空間大小,使得每個樹節點可以存儲更多的索引元素,從而減小樹的高度。
-
B+樹
- 特性:
- 非葉子節點不存儲data,只存儲索引(冗餘),可以放更多的索引
- 葉子節點包含所有索引字段
- 葉子節點用指針連接,提高區間訪問的性能
- 優勢:
- 樹高度較矮,針對大多數的表,2~4層即可滿足需求。
- 區間訪問性能較好
- 特性:
-
Hash
- 特性:對索引值進行hash,映射成對應數據行所在的磁盤文件指針。
- 弊端:
- 不支持範圍查詢
- 不支持模糊查詢
- 不支持排序
- 適用場景:大量等值查詢時
三. 存儲引擎下的索引實現
存儲引擎的粒度是表級別的。同一個數據庫下的不同表,可以使用不同的存儲引擎。
- MyISAM引擎
-
MyISAM爲聚集索引,索引文件和數據文件分離,索引數據保存的是對應行所在的磁盤文件指針
-
MyISAM使用3個文件保存數據:
- .frm:保存表的定義、結構等元信息
- .MYD:保存表中的所有數據行
- .MYI:保存表中的所有索引字段
-
InnoDB引擎
- InnoDB爲聚集索引,索引的葉子節點保存的是該行的所有數據
- InnoDB使用2個文件保存數據:
- .frm:保存表的定義、結構等元信息
- .ibd:同時保存InnoDB的數據和索引
- 對於主鍵索引,索引保存的是所在行的所有數據;對於非主鍵索引,索引保存的是主鍵索引的值
四. 聯合索引
- 聯合索引的所有列,構成一個節點,保存在B+樹中
- 聯合索引的最左前綴原則
五. 相關問題
-
爲什麼InnoDB表必須有主鍵,且推薦整型的自增主鍵?
InnoDB的表數據文件,就是按照B+樹組織的一個索引結構文件,因此一定要有一個主鍵。如果用戶沒有自定義主鍵,InnoDB會爲選擇一列唯一索引作爲主鍵。如果沒有唯一索引,InnoDB會爲每行數據生成一個唯一的整型自增數值rowId,作爲主鍵。
使用整型主鍵,索引查詢時,比較效率較高。且整型字段所佔空間較小。
使用自增主鍵,大部分的插入操作,都是在葉子節點鏈表上的addLast,不會涉及到節點的分裂和平衡,插入效率很高。
-
爲什麼InnoDB的的非主鍵索引,存儲的是主鍵索引的值,而不是像主鍵索引一樣直接存儲數據?
- 數據一致性角度:如果數據在多個索引處維護,那麼就存在數據一致性問題。插入一條記錄時,需要在每個索引樹上都插入一遍,就涉及到了分佈式事務的問題。
- 存儲空間角度:如果所有索引樹都保存數據,會造成大量的空間浪費。