一,前言
上一篇內容說到了MySQL存儲引擎的相關內容,及數據類型的選擇優化。下面再來說說索引的內容,包括對B-Tree和B+Tree兩者的區別。
1.1,什么是索引
索引是存儲引擎用於快速找到記錄的一種數據結構, 對性能的提升有很大的幫助,尤其當表中數量較大的情況下,索引正確的使用可以對性能提升幾個數量級。
但是索引經常被忽略,不恰當的索引對性能可能還會帶來負面效果。
1.2,什么時候添加索引
-
主鍵自動建立主鍵索引(唯一索引)
-
where字句中的列,頻繁作為查詢字段的列
-
表連接關聯的列
-
排序用到的列
-
索引的基數越大(選擇性大),索引的效率就越高
什么叫基數越大,比如手機號,每個列都具有不同的值,非常好區別,這個就適合建立索引,而性別這樣的字段,因為只有兩個值,以不適合建立索引,就是區分度高低的問題。
1.3,不適合添加索引
- 表中數據太少
- 頻繁修改的字段
- 數據重復且分布平均的字段
1.4,索引的分類
單值索引:即一個索引只包含單個列,一個表可以有多個單列索引。
唯一索引:索引列的值必須唯一,但是允許有空值。
復合索引:即一個索引包含多個列。
全文索引:使用fulltext創建全文索引。
在舊版MySQL中全文索引只能用在MyISAM表格的char、varchar和text的字段上。新版的MySQL5.6.24上InnoDB引擎也加入了全文索引。
使用方式:
- 創建索引:create [unique|fulltext] index 索引名 on 表名 (屬性名[長度][asc|desc])。
- 刪除索引:drop index 索引名 on 表名。
- 查看索引:show index from 表名。
具體使用方式這里就不詳細說明,接下來就說說關於索引的實現原理,Tree,B-Tree,B+Tree。
二,Tree
在總結B-Tree和B+Tree之前,先看看最基本的二叉樹結構吧,因為前兩種樹結構夠可以算是二叉樹的變種。
二叉樹是n(n>=0)個結點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根結點和兩棵互不相交的、分別稱為根結點的左子樹和右子樹組成。
二叉樹的特點:
- 每個結點最多有兩顆子樹,所以二叉樹中不存在度大於2的結點。
- 左子樹和右子樹是有順序的,次序不能任意顛倒。
- 從根節點出發,左子樹都是比根節點小的,而右子樹都是比根節點大的。
因此對於較平衡的二叉樹的查找性能,是幾乎接近於二分查找的,但是如果存入的數據都比根節點小,或者都比根節點大,則會出現以下情況。
這兩種情況分別是左斜樹和右斜樹,上述情況毫無疑問在二叉樹搜索時,效率是非常低的。因為它已經失去了樹的結構,不管是查詢節點,還是添加刪除等,都是對每個節點依次遍歷,直到查出目標節點為止。
另外還有一點也是很重要,如果二叉樹的字節點或多,一百萬,一千萬,甚至上億數據。對於較大數據量的二叉樹,會將其保存在磁盤中,那么問題來了。如果要查詢的數據在樹的底層,那么就勢必會造成多次的磁盤IO,而磁盤IO的讀取比內存讀取的速度要低100倍左右。這種情況下,不管是從性能來說,還是效率這都不是一個好的結果。
接着再說B-Tree結構,是二叉樹的一種升級版。
三,B-Tree
B樹又被成為平衡多路查找樹。
- 樹中每個結點最多含有m個節點(且m>2)。
- 除根結點和葉子結點外,其它每個結點至少有[m / 2,m]個孩子。
- 若根結點不是葉子結點,則至少有2個孩子(特殊情況:整棵樹只有一個根節點)。
- 所有葉子結點都出現在同一層。
在B-Tree或者B+Tree中,都會存在一個關於度的概念,也就是上面提到的m值。什么是度,可以說是我們自定義的一個閾值,當節點數量達到這個閾值時,樹的結構便會發生變化,此時便轉變成B-Tree結構。
現在,設定度(m)為3,首先我們先插入兩個節點:
發現在B樹結構中,當插入9節點時,並沒有成為8節點的右子樹,這是為什么。首先在於這就是B樹的結構特點,沒有成為8節點的右子樹是不是就減少了樹的層級深度。其次就是我們設定B樹的度為3,接着將再添加10節點,看有什么變化。
這個時候已經達到最大值3,那么根據二叉樹的結構特點,將9提升為根節點,8和10分別為9的左右子節點。
繼續添加6
添加11
添加15
分析:
1,當添加11完成時,葉子節點全部都達到了度為2,而添加15時,由於比根節點9大,所以添加到右子樹中。則右子樹變成0010
,0011
,0015
。顯然達到我們設定的閾值,根據以上規則,將0011
提升為根節點。
2,從圖中可以看出,9的左邊都是比根節點小,9到11之間都是大於9小於11的,最后11的右邊都是大於11的。
3,最后我們再添加5,我們先來分析下結構會如何變化,5小於9,所以會在左邊,變成005
,006
,008
,這個時候節點數量變成3,根據規則006應該提升為根節點。但是根節點又會變成006
,009
,0011
,同樣達到閾值,那么將009
再提升為根節點。最終結果如圖:
以上就是B-Tree的原理總結,那么這與二叉樹有什么區別呢。最直觀的就是樹的層級變少了,同樣也不會出現左右斜樹的情況。
在InnoDB存儲引擎中有頁(Page)的概念,頁就是磁盤管理的最小單位。InnoDB存儲引擎中默認每個頁的大小為16KB。並且可通過參數innodb_page_size將頁的大小設置為4K、8K、16K。
在B-Tree中,每個節點都會攜帶一個key信息,用於保存該數據在表中的位置,同時也會將數據保存到節點中。當節點不是葉子節點時,父節點會攜帶對象的指針指向其子節點在磁盤中的位置。根據磁盤存儲的頁大小,如果每個葉子節點都攜帶較多的信息,那么在磁盤中占用的空間資源也會越多。顯然這不是一個好的現象,因此就出現B-Tree的優化版,B+Tree。
四,B+Tree
InnoDB存儲引擎就是用B+Tree實現其索引結構。
在B+Tree結構中,每一層非葉子節點只存儲key值信息,而葉子節點只存放數據信息。這種結構不僅節省磁盤的空間,對節點的查詢效率也大大提高了很多。
除此之外,非葉子節點的key最終會全部出現在葉子節點上, 這么說很抽象,請看演示效果。
首先添加7,8兩個節點。
接着添加9節點。
同樣度達到了3,將8提升為根節點。但是與B-Tree不同的是,在葉子節點中也存在8節點,這就是B+Tree結構的特點,然后再添加10節點。
以此類推,在最后的葉子節點中,整個樹中的key都在存在,那么這與B-Tree有什么區別呢。每個節點中沒有數據存儲,只有key值信息,在磁盤中會存儲更多的數據。
五,總結
思考一個問題:
對於查詢效率最快的數據結構,哈希表的效率要比樹狀結構快的多,那么MySQL存儲引擎為什么不采用哈希表結構存儲數據,原因就是哈希表是不能進行范圍查找。
本篇博客並沒有講述對索引使用的優化,只系統闡述了MySQL索引的底層機制,那么使用索引優化,查詢優化,庫表結構優化會在最后一篇博客中全部分享完。
以上內容均是自主學習總結,如有錯誤歡迎留言指正。
感謝閱讀!