「記錄」第二章:MYSQL索引數據結構分析

本章從沒有數據結構開始分析,然後使用二叉樹,紅黑樹,B樹,B+樹這麼個過程,來分析MySQL爲啥使用B+Tree作爲索引的數據結構!內容部分是從各大博客而來,其中有自己的一些理解!如有不正之處歡迎指正

索引數據結構

  • 索引是MySQL高效獲取數據的排好序的數據結構
  • 索引存儲在文件
  • 常見數據結構
    • 二叉樹
    • 紅黑樹
    • HASH
    • BTREE

數據結構演化網址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html(常見的數據結構夠可以使用這個網站進行插入,刪除,查詢操作,利於理解數據結構演變);


沒有數據結構:

如果沒有用索引,如下圖,條件會與每一行數據作比對,如果是等於操作,滿足條件及停止,如果是範圍性查詢,會和所有數據比對,效率極低,其中涉及到磁盤的工作原理,頻繁的尋道是查詢速度慢的主要原因。

磁盤存儲原理

  1. 尋道時間(速度慢費事)
  2. 旋轉時間(速度較快)

二叉查找樹(BST)

二叉查找樹(BST,Binary Search Tree),也叫二叉排序樹,在二叉樹的基礎上需要滿足:任意節點的左子樹上所有節點值不大於根節點的值,任意節點的右子樹上所有節點值不小於根節點的值。

上面的沒有用數據結構特別耗時,下面爲二叉樹數據結構存儲數據是查詢數據的示意圖,兩次就可以查到數據,優化了查詢速度

二叉樹插入數據的特點:

每次插入從頂級節點開始判斷,如果插入的節點值小於當前節點,插入的數據將向左邊的子樹移動,如果大於當前節點,插入的數據項右邊的子樹移動;如果移動方沒有節點,直接插入移動的方向;如果有節點,將插入的數據和當前節點的值進行比較,小於向左移動,大於向右移動,以此類推,直至節點插入。

由於數據插入的特點,如果索引列是遞增的,就會退化爲列表,具體圖示在紅黑樹裏面的對比圖中可以看到。


 

平衡二叉樹(AVL):旋轉耗時

AVL樹是嚴格的平衡二叉樹,所有節點的左右子樹高度差不能超過1;AVL樹查找、插入和刪除在平均和最壞情況下都是O(lgn)。

AVL實現平衡的關鍵在於旋轉操作:插入和刪除可能破壞二叉樹的平衡,此時需要通過一次或多次樹旋轉來重新平衡這個樹。當插入數據時,最多只需要1次旋轉(單旋轉或雙旋轉);但是當刪除數據時,會導致樹失衡,AVL需要維護從被刪除節點到根節點這條路徑上所有節點的平衡,旋轉的量級爲O(lgn)。

由於旋轉的耗時,AVL樹在刪除數據時效率很低;在刪除操作較多時,維護平衡所需的代價可能高於其帶來的好處,因此AVL實際使用並不廣泛。


 

紅黑樹

二叉樹有缺點,如果插入的數據是遞增的,二叉樹退化成列表,依次查找,耗時長;所以對二叉樹做出了優化,也就是紅黑樹

                               

與AVL樹相比,紅黑樹的查詢效率會有所下降,這是因爲樹的平衡性變差,高度更高。但紅黑樹的刪除效率大大提高了,因爲紅黑樹同時引入了顏色,當插入或刪除數據時,只需要進行O(1)次數的旋轉以及變色就能保證基本的平衡,不需要像AVL樹進行O(lgn)次數的旋轉。總的來說,紅黑樹的統計性能高於AVL。

因此,在實際應用中,AVL樹的使用相對較少,而紅黑樹的使用非常廣泛。例如,Java中的TreeMap使用紅黑樹存儲排序鍵值對;Java8中的HashMap使用鏈表+紅黑樹解決哈希衝突問題(當衝突節點較少時,使用鏈表,當衝突節點較多時,使用紅黑樹)。

對於數據在內存中的情況(如上述的TreeMap和HashMap),紅黑樹的表現是非常優異的。但是對於數據在磁盤等輔助存儲設備中的情況(如MySQL等數據庫),紅黑樹並不擅長,因爲紅黑樹長得還是太高了。當數據在磁盤中時,磁盤IO會成爲最大的性能瓶頸,設計的目標應該是儘量減少IO次數;而樹的高度越高,增刪改查所需要的IO次數也越多,會嚴重影響性能。

 

紅黑數特點:

  • 每個節點或者是黑色,或者是紅色。
  • 根節點是黑色。
  • 每個葉子節點(NIL)是黑色。 [注意:這裏葉子節點,是指爲空(NIL或NULL)的葉子節點!]
  • 如果一個節點是紅色的,則它的子節點必須是黑色的。
  • 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。

二叉樹和紅黑樹的比較


 

HASH(MySQL使用的索引之一)

HASH索引基於哈希表實現,只有精確匹配索引所有列纔有效,對於每一行數據,存儲引擎都會對索引列進行哈希運算,得到一個哈希碼(HASH CODE),哈希索引將所有的哈希碼存儲在索引中,同時在hash表中保存指向每個數據行的指針,查詢效率自然特別高;

由於哈希碼的特性, 決定了範圍查詢索引將不生效,會造成全表掃描,性能大大降低;只有做匹配查詢,效率高,所以除外特殊場景外,實際使用情況並不多;


 

B樹(平衡多路查找樹)

上面已經說過,紅黑樹更適合內存中使用,而B樹就是爲了磁盤存儲設備而設計的一種平衡查找樹。

首先先需要了解磁盤和虛擬內存的數據交換的一些原理:Windows計算機的頁大小爲4KB,也就是說,需要把應用程序按照4KB的頁來進行切分,以頁(page)爲單位放到磁盤中,然後進行置換。通常計算性能不同,每次能交換多少也也不同;

對於B樹需要了解:

度:節點的數據存儲的個數,下圖中對應的就是每個磁盤塊中可以容納的數據的多少

特點:葉節點具有相同的深度;葉節點的指針爲空;節點中的key從左到右遞增排列

B樹其實就是擴大了橫向深度,減少了縱向的深度,從而不影響存儲的數據容量:因爲內存從磁盤中獲取數據是按頁讀取的,假設每個磁盤塊是一頁,一次IO操作就可以將磁盤塊讀到內存中,然後在該節點中根據索引判斷數據是否是當前磁盤快中,在直接取出,如果不在,由於每層的索引都是遞增的,且每兩個索引之間也有索引指向某個磁盤塊,指針快速定位到想要的數據在第二層的哪個磁盤塊從而將想要的磁盤塊直接讀到內存匯中,以此類推!一般縱向深度最多3~5,縱向深度是幾,對應次數IO就檢索出來了;相比於之前的 BST 多了在每一個磁盤頁的索引比較,但是因爲磁盤頁已經被磁盤 IO 操作讀取到了內存中。因爲內存 IO 操作比磁盤 IO 操作省時很多根本不在一個數量級所以可以忽略不計,所以磁盤 IO 操作仍然是最重要的性能指標。

B 樹相比於二叉搜索樹壓縮了深度,所以磁盤 IO 會比二叉搜索樹少,能有效地提高新能,所以 B 樹更適合索引。


 

B+樹(MySQL默認使用的是B+Tree)

B+樹是B樹的一種進化體,它更適合存儲索引結構,其中我們所知的MyISAMInnoDB存儲引擎用的數據結構都是B+樹,不同的是MylSAM存儲引擎索引和數據是分開存儲的,分別在不同的文件,而InnoDB則是將索引和數據放在一個文件裏面,MyISAM的B+樹的葉子節點存儲着索引以及對應數據的地址,而InnoDB葉子節點存儲的是索引及所在行其他列的數據。

B樹的索引和數據都存儲在節點上,如果數據特別大,會使得磁盤塊內的索引大大減少,就是說減少了橫向深度,增加了縱向深度,使得IO次數大大增加;

B+樹的非葉子節點只存儲索引及指針,葉子節點存儲所有索引及數據,這樣存儲橫向深度更大,縱向深度更小,大大介紹了IO的次數;同時每個葉子節點都有下個葉子節點的指針,範圍查詢也變得方便許多;雖然非葉子節點的索引是冗餘的,但是相對於更多次數的IO操作來說,可以忽略不計,適當的冗餘是可以接受的。

 


參考鏈接(如涉及侵權問題,請及時聯繫我):

https://blog.csdn.net/caijunsen/article/details/83045985

https://www.cnblogs.com/kismetv/p/11582214.html

https://www.cnblogs.com/tiancai/p/9024351.html


 

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