關係型數據庫索引,二叉樹、平衡二叉樹、多路平衡樹B-Tree、B+Tree,聚簇索引、非聚簇索引,聚集索引、非聚集索引

一、索引是什麼?

       索引是爲了加速對錶數據行的檢索而創建的分散存儲的數據結構。

      索引的工作機制 大概如下圖:

如上圖可知,索引是一種數據結構,它保存了對應數據表中列的地址或數據(根據不同數據表引擎而定)

那麼問題來了,用索引就是要加快數據的查詢,單靠映射是沒有意義的,需要一套能快速查找的方案,而索引的算法需要依次從如下幾個快速查找算法來理解:

1.二叉樹查找 binary search tree

2.平衡二叉樹查找 balanced binary search tree

3.多路平衡查找樹 B-Tree

4.加強版多路平衡查找樹(絕對平衡查找樹)B+Tree

 

二、二叉樹

二叉樹結構圖如下:

比如我們要查找9,那麼從根節點10開始查,9<10 所以向左邊子節點繼續找,與子節點5對比,9>5 向右邊子節點繼續找,9>7 向右子節點繼續找,9=9 命中查找結果。

如果添加一個數則也是每層對比,對比小於當前節點值的向左字節點,大於當前節點值的向右,直到末尾,比如上圖增加一個20的數據(用此網站可以模擬:https://www.cs.usfca.edu/~galles/visualization/BST.html

通過如上圖可以知道,二叉樹上添加數據,如果再添加21、22、23..... 那麼樹的層級會越來越高,我們知道數據是存儲在硬盤裏面的,每一層的數據對比,需要從硬盤中取出數據進行對比,那也就是沒達到一層都進行了一次I/O操作,所以爲了使樹的分支左右平衡(即左右分支層次相對平衡),減少查找時的I/O操作次數,所以需要改良二叉樹的分支規則,那麼平衡二叉樹就能更好的減少I/O操作次數。

三、平衡二叉樹

數據結構如下圖:

每一個節點 分三部分:

1.關鍵字(要查找的關鍵字)

2.數據區(要查找的數據的存儲地址或數據)

3.子節點引用(指向子節點的指針)

 

數結構的平衡是相對平衡的,即葉子節點不一定都在同一個層。

在數據結構中加 16、17、18 的變化

  

從如上圖增加 3個數可知道,爲了保持樹的結構左右相對平衡,儘量減少樹的層,添加數的時候,要保證末端的葉子節點層數,不能超過最小層2個層次,一旦超過2個層次將對分支結構進行重構來保證結構的相對平衡。

當數據比較少的時候,平衡二叉樹的層次不會太高,當數據量越來越多的時候,層數也會越來越高,查找數據的時候I/O操作同樣也會越來頻繁(數據所在的層次決定了I/O操作的次數),這種算法依舊沒有很好的利用操作系統和磁盤的數據交換特性,那麼我們就需要在分支數上進行加強,多路平衡查找樹就能使每個節點能產生更多的分支,大大降低了樹的層數,同時每個節點能檢索的數據比平衡二叉樹要多。

 

三、多路平衡查找樹(B-Tree)

數據結構圖如下:

注意:這裏的平衡是絕對平衡,即保證所有的葉子節點都在樹的同一層,如新增的數據不能保證絕對平衡,則對樹進行重構。

B-Tree (2-3)的每個節點中包含:關鍵字(最多2個)、對應關鍵字的數據存儲區、子節點的引用(3個)

數據查找的規則(根據上圖數據): 

X < 17 ->P1  所查找數據小於17 去P1指向的子節點繼續查找

17 < X < 35 ->P2 所查找的數據大於17 且小於35 則去P2所指向的子節點繼續查找

X > 35 ->P3 所查找的數據大於35 則去P3所指向的字節點繼續查找

X = 17 命中,當查找的數據等於當前的節點的值,那麼就命中了,結束查找。

 

B-Tree (2-3)增加數據的時候,需要保證樹的結構絕對平衡,如下是添加過程的示例:

 

根據如上的模擬,爲了保證樹的絕對平衡,葉子節點都在同一層,添加數據的時候都會按照規則進行調整。(具體的重構算法沒必要深究,理解B-Tree (2-3)結構規則即可)

規則(如下的m即 分支數)

  • 每個節點最多隻有m個子節點。
  • 每個非葉子節點(除了根)具有至少⌈ m/2⌉子節點。(⌈ m/2⌉ 向上取整 3/2=2)
  • 如果根不是葉節點,則根至少有兩個子節點。
  • 具有k個子節點的非葉節點包含k -1個鍵。
  • 所有葉子都出現在同一水平,沒有任何信息(高度一致)。

B-Tree算法對數據查找效率已經非常好了,爲什麼mysql索引算法沒有用B-Tree算法而是用了B+Tree? 當然是B+Tree的綜合查詢效率更加優秀。

 

四、B+Tree(加強版多路平衡查找樹)

數據結構圖如下:

與B-Tree對比:

1.B+Tree除了葉子節點,每個字節點沒有數據區,只有 關鍵字 和 子節點引用

2.每個子節點(包括葉子節點)都包含了父節點所屬的關鍵字

3.所有葉子節按升序排列在同一層,且葉子節點存儲了關鍵字對應表的行數據(或行的地址),即每次查找都會到最終的葉子層拿到目標數據。

.B+Tree的查找規則(如上圖)查找1

1 <= x < 28 ->p1 (根節點) 查找的1等於1 則去p1的字節點繼續查找

1 <= x < 10 ->p1 (子節點-非葉子節點) 查找的1等於1 則去p1的字節點繼續查找

1=x (葉子節點) 命中,找到葉子節點中對應的數據或數據地址,查找結束。

28 <= x < 66 ->p2  如果查找的值 大於等於 28  小於66 則去p2子節點繼續查找,直到葉子節點找到數據

66 <= x ->p3  如果查找的值大於當前節點最大值,那麼去p3子節點繼續查找 ,直到葉子節點

注意:從如上的規則中我們可以 明確直到,各節點(根節點、子節點)都是左閉合的,即樹的左側的數據分支判斷範圍在 節點值的最小值和中間值之間, 而右側是開放的,大於當前節點最大 值就往右邊節點走。

 

B-Tree與B+Tree的區別

1. B樹每個節點都存儲數據,所有節點組成這棵樹。B+樹只有葉子節點存儲數據(B+數中有兩個頭指針:一個指向根節點,另一個指向關鍵字最小的葉節點),葉子節點包含了這棵樹的所有數據,所有的葉子結點使用鏈表相連,便於區間查找和遍歷,所有非葉節點起到索引作用。

2. B樹中葉節點包含的關鍵字和其他節點包含的關鍵字是不重複的,B+樹的索引項只包含對應子樹的最大關鍵字和指向該子樹的指針,不含有該關鍵字對應記錄的存儲地址。

3. B樹中每個節點(非根節點)關鍵字個數的範圍爲[m/2(向上取整)-1,m-1](根節點爲[1,m-1]),並且具有n個關鍵字的節點包含(n+1)棵子樹。B+樹中每個節點(非根節點)關鍵字個數的範圍爲[m/2(向上取整),m](根節點爲[1,m]),具有n個關鍵字的節點包含(n)棵子樹。

4. B+樹中查找,無論查找是否成功,每次都是一條從根節點到葉節點的路徑。

關係型數據庫,數據的查找中範圍查找是非常多的,根據B-Tree與B+Tree的區別可以知道,B+Tree在遍歷數據時更具有優勢。所以mysql索引算法最終選擇了B+Tree

 

五、B+Tree結構 具體應用於mysql索引的形式

因爲mysql數據庫 表的搜索引擎不同(InnoDB與Myisam),所體現的形式有所不同。

1)Myisam索引B+Tree算法的體現形式如下圖:

在myisam中,索引和具體數據是分開文件存儲的,樹的葉子節點存儲了對應數據行的地址(指針),最終數據需要拿着葉子節點匹配到的地址去獲取。

當一個表中有多個索引時,多個索引都放置在同一個MYI索引文件中。

 

2)InnoDB索引B+Tree算法的體現形式如下圖:

索引結構與數據是在同一個文件當中的(IBD),葉子節點直接存儲了數據行的數據。

InnoDB引擎的表必須有主鍵索引(創建表的時候指定主鍵就會創建)

在InnoDB引擎中,創建的輔助索引,它的葉子節點所存儲的值是主鍵的值,如果觸發輔助索引,需先根據當前索引找到目標數據的主鍵值,然後再在主鍵索引中找到目標行數據,實際上是進行了兩次索引查找。 

 

InnoDB與Myisam的對比:

爲什麼InnoDB直接將數據存儲在主鍵索引的葉子節點上? 因爲可以直接拿到查找的數據

爲什麼InnoDB輔助索引葉子節點存儲的是主鍵值,而不是直接存儲要查找的數據行? 因爲在數據表中更改了非主鍵列的數據,數據庫不用去維護輔助索引的結構,只需要去修改主鍵索引就行。

所以,InnoDB引擎的寫性能要比Myisam強,而Myisam的讀性能比Innodb強。

 

六、索引的幾大原則

1.列的離散性(如下圖):

所謂的離散型就是,當前列的數據 唯一的數據越多越好,如上圖所示 sex列 重複的數據佔一半,name列沒有重複的數據,那麼name的離散性就要比sex列的好。

離散性越高,選擇性就越好。離散性越高則查找的目標數據越明確,範圍越小。

 

2.最左匹配原則(如下圖):

之前的結構圖都是用數字來進行對比的(因爲數字更簡單直接),而數據庫的索引實際上是通過字符序列來對比排序的,而字符是通過編碼而來的, 比如ASCII碼;

不恰當的比喻:

ABC  = 91 92 93          ACD = 91 93 94    通過從左往右對比最終的字碼,ABC < ABD  

 

七、聯合索引

即多列組合成一個索引

 

 

覆蓋索引

 

 

八、聚簇索引與非聚簇索引(是從數據存儲上來進行區分的

聚簇索引:對磁盤上的數據物理位置重新組織以按照特定的一個或者多個列的值排序的算法進行排列,且數據行與葉子節點存儲在一起,搜索到葉子節點也就能直接拿到數據。一個表只能有一個聚族索引。InnoDB主鍵索引就是聚簇索引

非聚簇索引:葉子節點的值有指針指向數據行存儲的位置,數據行沒有存儲在葉子節點,最終數據需要根據葉子節點的指針去數據文件上獲取。myisam的主鍵索引和輔助索引都是非聚簇索引

 

九、聚集索引與非聚集索引(葉子層排序方式 與數據的物理排序 進行區分)

1、聚集索引

聚集索引:指索引項的排序方式和表中數據記錄排序方式一致的索引 

也就是說聚集索引的順序就是數據的物理存儲順序。它會根據聚集索引鍵的順序來存儲表中的數據,即對錶的數據按索引鍵的順序進行排序,然後重新存儲到磁盤上。因爲數據在物理存放時只能有一種排列方式,所以一個表只能有一個聚集索引。

聚集索引會降低 insert,和update操作的性能,所以,是否使用聚集索引要全面衡量。

2、非聚集索引: 索引順序與物理存儲順序不同

 

 

本文通過如下重新整合:

https://v.qq.com/x/page/k0849vd8k0h.html       索引算法的演變 

https://blog.csdn.net/guzhangyu12345/article/details/96423704  索引分類

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章