深入理解索引和AVL樹、B-樹、B+樹的關系


什么是索引

索引時數據庫的一種數據結構,數據庫與索引的關系可以看作書籍和目錄的關系。當用戶通過索引查找數據時,好比用戶通過目錄查詢某章節的某個知識點。這樣可以幫助用戶提高查找速度。所以,索引可以提高數據庫的性能。

索引的分類

從物理存儲角度:
聚簇索引和非聚簇索引

從數據結構角度:
B-樹、B+樹、hash索引、FULLTEXT索引、R-Tree索引

從邏輯角度:

  • 主鍵索引:主鍵索引是一種特殊的唯一索引,不允許有空值
  • 普通索引/單列索引
  • 復合索引/多列索引:復合索引指多個字段上創建的索引,只有在查詢條件中使用了創建索引時的第一個字段,索引才會被使用。使用復合索引時遵循最左前綴集合
  • 唯一索引或者非唯一索引
  • 空間索引:空間索引是對空間數據類型的字段建立的索引,MYSQL中的空間數據類型有4種,分別是GEOMETRY、POINT、LINESTRING、POLYGON

索引和AVL樹、B-樹、B+樹的關系

傳統用來搜索的平衡二叉樹有很多,如 AVL 樹,紅黑樹等。這些樹在一般情況下查詢性能非常好,但當數據非常大的時候它們就無能為力了。原因當數據量非常大時,內存不夠用,大部分數據只能存放在磁盤上,只有需要的數據才加載到內存中。一般而言,磁盤和內存的數據交互是影響系統性能的瓶頸,所以索引的效率依賴於磁盤 IO 的次數。

AVL樹、紅黑樹

即平衡二叉搜索樹,它的特點是在二叉搜索樹(BST)的基礎上,要求每個節點的左子樹和右子樹的高度差至多為1。這個要求使AVL的高度h = logn,底數為2,避免了BST可能存在的單鏈極端情況(h = n)。

它通過旋轉來保持平衡的,而旋轉是對整棵樹的操作,若部分加載到內存中則無法完成旋轉操作,所以AVL樹的操作要全部加載加到內存中。

紅黑樹則是BST得另一個變種,增加了顏色限制,它也需要通過旋轉調整結構,所以AVL樹和紅黑樹基本都是存儲在內存中才會使用的數據結構。在大規模數據數據存儲的時候,顯然不能將全部數據全部加載進內存,因此如果采用紅黑樹和AVL樹,就會造成頻繁IO。所以這類平衡二叉樹在數據庫和文件系統上的選擇就被 pass 了。

索引的原理其實是不斷的縮小查找范圍,就如我們平時用字典查單詞一樣,先找首字母縮小范圍,再第二個字母等等。平衡二叉樹是每次將范圍分割為兩個區間。為了更快,我們可以每次將范圍分割為多個區間,區間越多,定位數據越快越精確,這就是B、B+樹這類樹的由來。

B-樹

也叫B樹,即平衡多路查找樹,m階B樹表示節點可擁有的最多m個孩子,2-3樹是3階B樹,2-3-4樹是4階B樹。多叉樹可以有效降低樹的高度,h=log_m(n),m為log的底數。

B-樹的特點:

  1. 任意非葉子結點最多只有 M 個兒 子, M>2
  2. 根結點的兒子數為 [2, M]
  3. 除根結點以外的非葉子結點的兒子數為 [M/2, M]
  4. 每個結點存放至少 M/2-1 (向上取整)和至多 M-1 個關鍵字, M> 2
  5. 非葉子結點的關鍵字個數 = 指向孩子的指針個數 -1 ;
  6. 非葉子結點的關鍵字: K[1], K[2], …, K[M-1] , K[i] < K[i+1]
  7. 非葉子結點的指針: P[1], P[2], …, P[M] ;其中 P[1] 指向關鍵字小於 K[1] 的子樹, P[M] 指向關鍵字大於 K[M-1] 的子樹,其它 P[i] 指向關鍵字屬於 (K[i-1], K[i]) 的子樹
  8. 所有葉子結點位於同一層

B-樹結構如下圖:

在普通平衡二叉樹中,插入刪除后若不滿足平衡條件則進行旋轉 操作,而在B樹中,插入刪除后不滿足條件則進行分裂及合並操作。所以,B樹並不需要把節點一次性加載到內存,而B樹的查找過程是一個順指針查找節點和節點中查找關鍵字的交叉過程。

B樹查找雖然很方便,但是存在一個缺陷,如果我們要完成對數據的遍歷,那么需要不斷在內外存做數據交互,這顯然是影響性能的。為了解決這個問題,提出了B+樹。

B+樹

B-樹的變體,也是一種多路搜索樹,與B-樹的區別是:

  1. 非葉子結點的子樹指針與關鍵字個數相同,即n 個 key 值的節點指針域為 n 而不是 n+1
  2. 非葉子結點的子樹指針 P[i] , 指向關鍵字值屬於 [K[i], K[i+1]) 的子樹( 左閉右開,B樹是全開區間)
  3. 為所有葉子結點增加一個鏈指針
  4. B+樹的key 的副本存儲在內部節點,真正的 key 和 data 存儲在葉子節點上 。

B+樹結構如下圖:

B+樹的兩個明顯特點:

  • 數據只出現在葉子節點
  • 所有葉子節點增加了一個鏈指針

總結一下B樹和B+樹的不同:

  1. 因為內節點並不存儲 data,所以一般B+樹的葉節點和內節點大小不同,而B-樹的每個節點大小一般是相同的。在磁盤存儲中,為了滿足局部性原理,一般會給每個結點分配一頁的存儲容量,這使得B+樹的非葉節點可以保存更多的key,減少了查找時的磁盤IO次數。
  2. B+ 樹只有達到葉子結點才命中( B樹可以在非葉子結點命中),其查詢時間復雜度固定為 log n,查詢效率很穩定,而B-樹查詢時間復雜度不固定,與 key 在樹中的位置有關。
  3. B+樹葉節點兩兩相連可大大增加區間訪問性,可使用在范圍查詢,而B樹每個節點 key 和 data 在一起,無法區間查找。

SQL和NoSQL索引

MongoDB采用B樹作為索引,MySQL采用B+樹作為聚簇索引的數據結構。

這是因為關系型數據庫和非關系型數據的設計方式上的不同,導致在關系型數據中,遍歷操作比較常見,因此采用B+樹作為索引比較合適。而在非關系型數據庫中,單一查詢比較常見,因此采用B樹作為索引,比較合適。

MongoDB 是文檔型的數據庫,是一種 nosql,它使用類 Json 格式保存數據。文檔型數據庫和我們常見的關系型數據庫不同,一般使用 XML 或 Json 格式來保存數據,歸屬於聚合型數據庫,鍵值型的redis也屬於聚合型。對於聚合型數據庫,key-value聚合在一起的b樹可以減少磁盤 IO。

聚合型數據庫的結構:

參考

談談你對mysql索引的認識
MongoDB及Mysql背后的B/B+樹
為什么 MongoDB (索引)使用B-樹而 Mysql 使用 B+樹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM