目標
- 1、索引數據紅黑樹、Hash、B+樹詳解
- 2、千萬級數據表如何用索引快速查找
- 3、如何基於索引B+樹准確建立高性能索引
- 4、聯合索引底層數據結構是怎樣的
- 5、聚集索引與覆蓋索引
- 6、Mysql的最左前綴原則
- 7、為什么推薦使用自增主鍵做索引
- 8、Mysql索引優化規則
索引的本質
按照官方的定義,索引就是按用戶任意指定的字段對數據進行排序的一種數據結構。
- 使用InnoDB存儲引擎時,在插入數據的時候,會自動把字段排好序(聚集);
- 而用MYISAM存儲引擎時,默認按插入數據的順序進行存儲,不會排序(堆表)。
索引的數據結構
- 二叉樹
- 紅黑樹
- Hash表
- B-Tree
假如現在有一個2列7行的表,如下圖:
上圖左邊的:
0x07
、0x56
這些表示的是數據在磁盤上存儲的首地址指針。
按照不同的數據結構生成的索引也是不同的,比如:
下面是以 COL2 字段建的索引:
- 二叉樹
二叉樹的特點就是: 它右邊的子元素是大於等於它的父元素,而左邊的子元素是小於它的父元素的。
缺點:如果是插入了有小到大一次遞增的索引是,數據結構就變成了鏈表了。結果就是建了索引跟沒建一樣,走的就是全表掃描。
- 紅黑樹
紅黑樹的本質是一個二叉平衡樹,當樹一邊鏈表太長的時候,它會自動平衡。
缺點: 樹的高度太高,查找的次數多。
-
Hash表
-
hash算法算出字段的hash值,然后把hash值跟磁盤數據列地址指針做高速映射。
-
hash在等值查找的時候,性能是非常不錯,但是在范圍查找的時候效率就不行了。因為還是得挨個遍歷出來。
-
B Tree
- 頁子節點具有相同的深度,頁節點的指針為空
- 所有索引元素不重復
- 節點中的數據索引從左到右遞增排列
缺點:沒有雙向指針,范圍查找的時候不如b+樹。而且,b樹的葉子節點存儲了data,這樣整個樹在高度h<=3時存儲的索引少了很多。
- B+Tree
- 非頁子節點不存儲數據(data),只存儲索引(冗余),可以放更多的索引。
- 頁子節點包含所有索引字段。
- 頁子節點用指針連接,提高區間訪問性能。
現在來看一下B+樹,可以存放多少索引元素:
mysql中存儲數據的單位是頁,跟操作系統類似,只不過操作系統中的大小為4kb,而mysql的頁的大小是16kb。
假設圖中的索引是一個bigint類型的主鍵索引,bigint類型占8位,也就是說一個索引數據是8b,而圖中的空白元素實際上是指下一個子節點的磁盤文件地址,默認占6b。這樣計算一下: 16kb/(8+6) = 1170。也就是說一個頁大概可存儲1170個索引。這是樹第一層非葉子節點,可以存這么多。第二層也是非葉子節點,同理可算: 1170 x 1170 = 1368900。可以存儲1368900個索引。第三層則是頁子節點,它沒有下一層,但是每一個索引下面會有一個data
,這個data
有可能是索引所在行的磁盤文件地址,有可能是索引所在行的其他列的數據。這個不同的存儲引擎,放的東西是不一樣的。現在假設這個data
里放的是索引所在行的其他字段信息,這樣它占的空間比較大,所以假設索引+data為1kb的大小,這樣,每個頁就有16個索引,所以總共可以放:1170x 1170 x 16 = 21902400 個索引。 這個數量級完全夠我們用的,所以mysql采用B+樹這種數據結構來存儲索引。
B+樹的根節點是放在內存的,索引在sql查詢的時候,如果樹的高度h=3,最多也只會進行2次磁盤IO。
MYISAM存儲引擎
MYISAM索引文件和數據文件是分離的。(非聚集)
查看mysql文件存儲位置:
show global variables like "%datadir%";
MYISAM存儲引擎,在磁盤上對應有3個文件: xx.frm、xx.MYD、xx.MYI 文件,沒有截圖就不放了。
下面看看對應的邏輯圖:
假設Col1是索引字段,那么圖中,上部分B+樹結構數據就是放在 xx.MYI 文件里,而下面的表一條一條數據就是放在 xx.MYD 文件中的。
InnoDB存儲引擎
InnoDB索引文件和數據是在一起的,存在於一個文件中。(聚集)
- 表數據文件本身就是按照B+樹組織的一個索引結構文件
- 聚集索引葉子節點包含了完整的數據記錄
- 為什么InnoDB表必須要有主鍵,並且推薦整形自增主鍵
- 答:①、InnoDB規定是按照主鍵索引把數據組織起來的,如果沒有顯式定義主鍵的話,mysql會默認查找表中的字段,看有沒有唯一性的字段。如果有,那么就把它作為主鍵。如果沒有唯一性的字段,那么mysql會隱式的創建一個字段(rowId)自增的整形,來作為主鍵索引。
- 答:②、1、使用整形的自增,很簡單如果不是整形的話,比如說UUID,那么UUID這種字符串進行比較(ASCII碼)大小,肯定沒有整形的數據(1<2)這種效率高。2、而且使用整形比UUID更省空間。3、自增的話就保證每次插入數據都在后面插入,因為b+樹要求葉子節點的數據要從左到右一次遞增的。(不自增的話,可能插入的數據在前面,會導致葉子節點分裂,然后做一次平衡,性能和效率會降低)
- 為什么非主鍵索引結構葉子節點存儲的是主鍵值(一致性和節省存儲空間)
聚集索引一般都要比非聚集索引查詢效率要高,因為聚集索引(聚簇索引)只需要查一個文件而非聚集索引(稀疏索引)要查2個文件(.MYI和.MYD)
聯合索引
多個字段組成聯合索引。聯合索引的底層存儲結構是什么樣的?
上圖是由3個字段組成的聯合索引。而且,不管是單值索引還是聯合索引,它的葉子節點都是從左到右遞增排好序的。所以它的順序是按照(a,b,c)字段的先后順序排的。
最左前綴原則
如果索引是由多個字段組成的聯合索引,要遵循最左前綴原則。也就是:查詢要從索引的最左前列開始並且不跳過索引中的列。