MySQL 索引講解
MySQL索引
索引是幫助MySQL高效獲取資料的排好序的資料結構。
索引的資料結構:
- 二叉樹
- 紅黑樹
- Hash表
- B-Tree
索引的節點儲存的是key(索引列欄位),value(行資料磁碟檔案的地址指標)。從索引表中找的時候,都是從根節點去找。(二叉樹的資料結構)
二叉查詢樹:
採取二分查詢的思想,O(logN) 的複雜度就可以完成對資料的查詢任務,查詢所需的最大次數等同於二叉樹的高度。
它的特性:
- 左子樹上所有節點的值,小於或等於根節點的值
- 右子樹上節點的值,大於或等於根節點的值
缺點:插入值時,可能會出現"單條腿長"的現象,導致多次插入新節點而不平衡的現象,這時紅黑樹就出現了。
紅黑樹:
也叫二叉平衡樹。說它平衡的意思就是,它不會變瘸子
,左腿或右腿特別長的現象。
它的特性:
- 節點都是紅色或者黑色
- 根節點都是黑色
- 每個葉子的節點都是黑色空節點
- 每個紅色節點兩個子節點都是黑色的
- 從任意節點到每個葉子的所有路徑都包含相同的黑色節點
紅黑樹的高度雖然有一定的控制,而資料庫當中一般要把索引樹的高度控制在3-5層,這點紅黑樹顯然無法做到。
B-Tree:
B-Tree是為磁碟等外儲存裝置設計的一種平衡查詢樹,是一種多路平衡搜尋樹。
不像紅黑樹只有2個子節點。既然有多個子節點,樹的高度就可以控制了,同時它也跟紅黑樹一樣,資料是排序的,可以快速查詢;
它的特性:
- 每個節點最多含有m個孩子
- 根節點含有[2,m]個孩子
- 非葉子節點含有[[m/2],m]個孩子節點(向上取整的意思)
- 所有葉子節點都在同一層
-
每個節點佔用一個盤塊的磁碟空間,一個節點有兩個升序排序的關鍵字和三個指向子樹節點的指標,指標儲存是子節點磁碟塊地址。
-
兩個關鍵詞劃分成的三個範圍域對應三個指標指向的子樹的資料的範圍域。
以根節點為例,關鍵字為17和35,P1指標指向的子樹的資料範圍為小於17,P2指標指向的子樹的資料範圍為17~35,P3指標指向的子樹的資料範圍為大於35。
模擬查詢關鍵字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次記憶體查詢操作。由於記憶體中的關鍵字是一個有序表結構,可以利用二分法查詢提高效率。而3次磁碟I/O操作是影響整個B-Tree查詢效率的決定因素。
B+Tree:
B+Tree是在B-Tree基礎上的優化InnoDB儲存引擎就是用B+Tree實現其索引結構。
B-Tree的資料結構可以看出,每一個頁的儲存空間是有限的,如果data資料較大時會導致每個節點儲存的key數量很小,但儲存的資料量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁碟I/O次數,影響查詢效率。
在B+Tree樹中,所有資料記錄點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點只儲存key值資訊。這樣可以增大每個節點key值數量,降低B+Tree的高度
。
B+Tree與B-Tree不同:
- 非葉子節點只儲存鍵值資訊
- 所有葉子節點之間有一個鏈指標
- 所有記錄值都存放在葉子節點中
- 資料都在葉子節點上,並且增加了順序訪問指標,每個葉子節點都指向相鄰的葉子節點的地址。
- 相比B-Tree來說,進行範圍查詢時只需要查詢兩個節點,進行遍歷即可,提高了區間訪問效能(無需返回上層父節點重複遍歷查詢減少IO操作)
- B-Tree需要獲取所有節點,相比之下B+Tree效率更高。
為什麼要使用B+Tree?
一般來說,索引本身也很大,不可能全部儲存在記憶體中,索引往往以索引檔案的形式儲存的磁碟上。索引查詢過程中就要產生磁碟I/O消耗
,所以評價一個數據結構作為索引的優劣最重要的指標就是在查詢過程中磁碟I/O操作次數的漸進複雜度。簡單說:索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數。
對比上面的B+樹和紅黑樹,比如查詢節點21,紅黑樹要磁碟IO5次,而B+樹只要2次,也就是說磁碟IO次數大致為樹的高度,這樣B+樹就脫穎而出了。
B+Tree的高度一般都在2 ~ 4層。MySQL的InnoDB儲存引擎在設計時是將根節點常駐記憶體的,也就是說查詢某一鍵值的行記錄時最多隻需要1~3次磁碟I/O操作。
資料庫索引採用B+樹而不是B樹的主要原因: B+樹只要遍歷葉子節點就可以實現整棵樹的遍歷,而且在資料庫中基於範圍的查詢是非常頻繁的,而B樹只能中序遍歷所有節點,效率太低。
為什麼索引結構預設使用B-Tree,而不是hash,二叉樹,紅黑樹?
hash:雖然可以快速定位,但是沒有順序,IO複雜度高。
二叉樹:樹的高度不均勻,不能自平衡,查詢效率跟資料有關(樹的高度),並且IO代價高。
紅黑樹:樹的高度隨著資料量增加而增加,IO代價高。
如果只選一個數據,那確實是hash更快。但是資料庫中經常會選擇多條,這時候由於B+樹索引有序,並且又有連結串列相連,它的查詢效率比hash就快很多了。
而且資料庫中的索引一般是在磁碟上,資料量大的情況可能無法一次裝入記憶體,B+樹的設計可以允許資料分批載入,同時樹的高度較低,提高查詢效率。
為什麼官方建議使用自增長主鍵作為索引?
B+Tree的特點,自增主鍵是連續的,在插入過程中儘量減少頁分裂,即使要進行頁分裂,也只會分裂很少一部分。並且能減少資料的移動,每次插入都是插入到最後。總之就是減少分裂和移動的頻率。