1. 程式人生 > 資料庫 >Mysql中的B樹索引和B+樹索引的區別?

Mysql中的B樹索引和B+樹索引的區別?

  • 在B樹中,你可以將鍵和值存放在內部節點和葉子節點;但在B+樹中,內部節點都是鍵,沒有值,葉子節點同時存放鍵和值。

  • B+樹的葉子節點有一條鏈相連,而B樹的葉子節點各自獨立。

在這裡插入圖片描述

1 使用B樹的好處

B樹可以在內部節點同時儲存鍵和值,因此,把頻繁訪問的資料放在靠近根節點的地方將會大大提高熱點資料的查詢效率。這種特性使得B樹在特定資料重複多次查詢的場景中更加高效。

2 使用B+樹的好處

由於B+樹的內部節點只存放鍵,不存放值,因此,一次讀取,可以在記憶體頁中獲取更多的鍵,有利於更快地縮小查詢範圍。 B+樹的葉節點由一條鏈相連,因此,當需要進行一次全資料遍歷的時候,B+樹只需要使用O(logN)時間找到最小的一個節點,然後通過鏈進行O(N)的順序遍歷即可。而B樹則需要對樹的每一層進行遍歷,這會需要更多的記憶體置換次數,因此也就需要花費更多的時間

3 Hash索引和B+樹索引有什麼區別或者說優劣呢?

首先要知道Hash索引和B+樹索引的底層實現原理:

hash索引底層就是hash表,進行查詢時,呼叫一次hash函式就可以獲取到相應的鍵值,之後進行回表查詢獲得實際資料。B+樹底層實現是多路平衡查詢樹。對於每一次的查詢都是從根節點出發,查詢到葉子節點方可以獲得所查鍵值,然後根據查詢判斷是否需要回表查詢資料。

那麼可以看出他們有以下的不同:

  • hash索引進行等值查詢更快(一般情況下),但是卻無法進行範圍查詢。

因為在hash索引中經過hash函式建立索引之後,索引的順序與原順序無法保持一致,不能支援範圍查詢。而B+樹的的所有節點皆遵循(左節點小於父節點,右節點大於父節點,多叉樹也類似),天然支援範圍。

  • hash索引不支援使用索引進行排序,原理同上。
  • hash索引不支援模糊查詢以及多列索引的最左字首匹配。原理也是因為hash函式的不可預測。AAAA和AAAAB的索引沒有相關性。
  • hash索引任何時候都避免不了回表查詢資料,而B+樹在符合某些條件(聚簇索引,覆蓋索引等)的時候可以只通過索引完成查詢。
  • hash索引雖然在等值查詢上較快,但是不穩定。效能不可預測,當某個鍵值存在大量重複的時候,發生hash碰撞,此時效率可能極差。而B+樹的查詢效率比較穩定,對於所有的查詢都是從根節點到葉子節點,且樹的高度較低。

因此,在大多數情況下,直接選擇B+樹索引可以獲得穩定且較好的查詢速度。而不需要使用hash索引。

4 資料庫為什麼使用B+樹而不是B樹

  • B樹只適合隨機檢索,而B+樹同時支援隨機檢索和順序檢索;
  • B+樹空間利用率更高,可減少I/O次數,磁碟讀寫代價更低。一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟I/O消耗。B+樹的內部結點並沒有指向關鍵字具體資訊的指標,只是作為索引使用,其內部結點比B樹小,盤塊能容納的結點中關鍵字數量更多,一次性讀入記憶體中可以查詢的關鍵字也就越多,相對的,IO讀寫次數也就降低了。而IO讀寫次數是影響索引檢索效率的最大因素;
  • B+樹的查詢效率更加穩定。B樹搜尋有可能會在非葉子結點結束,越靠近根節點的記錄查詢時間越短,只要找到關鍵字即可確定記錄的存在,其效能等價於在關鍵字全集內做一次二分查詢。而在B+樹中,順序檢索比較明顯,隨機檢索時,任何關鍵字的查詢都必須走一條從根節點到葉節點的路,所有關鍵字的查詢路徑長度相同,導致每一個關鍵字的查詢效率相當。
  • B-樹在提高了磁碟IO效能的同時並沒有解決元素遍歷的效率低下的問題。B+樹的葉子節點使用指標順序連線在一起,只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在資料庫中基於範圍的查詢是非常頻繁的,而B樹不支援這樣的操作。
  • 增刪檔案(節點)時,效率更高。因為B+樹的葉子節點包含所有關鍵字,並以有序的連結串列結構儲存,這樣可很好提高增刪效率。

5 B+樹在滿足聚簇索引和覆蓋索引的時候不需要回表查詢資料,

在B+樹的索引中,葉子節點可能儲存了當前的key值,也可能儲存了當前的key值以及整行的資料,這就是聚簇索引和非聚簇索引。 在InnoDB中,只有主鍵索引是聚簇索引,如果沒有主鍵,則挑選一個唯一鍵建立聚簇索引。如果沒有唯一鍵,則隱式的生成一個鍵來建立聚簇索引。

當查詢使用聚簇索引時,在對應的葉子節點,可以獲取到整行資料,因此不用再次進行回表查詢。

6 什麼是聚簇索引?何時使用聚簇索引與非聚簇索引

  • 聚簇索引:將資料儲存與索引放到了一塊,找到索引也就找到了資料
  • 非聚簇索引:將資料儲存於索引分開結構,索引結構的葉子節點指向了資料的對應行,myisam通過key_buffer把索引先快取到記憶體中,當需要訪問資料時(通過索引訪問資料),在記憶體中直接搜尋索引,然後通過索引找到磁碟相應資料,這也就是為什麼索引不在key buffer命中時,速度慢的原因

澄清一個概念:innodb中,在聚簇索引之上建立的索引稱之為輔助索引,輔助索引訪問資料總是需要二次查詢,非聚簇索引都是輔助索引,像複合索引、字首索引、唯一索引,輔助索引葉子節點儲存的不再是行的物理位置,而是主鍵值

何時使用聚簇索引與非聚簇索引

在這裡插入圖片描述

7 非聚簇索引一定會回表查詢嗎?

不一定,這涉及到查詢語句所要求的欄位是否全部命中了索引,如果全部命中了索引,那麼就不必再進行回表查詢。

舉個簡單的例子,假設我們在員工表的年齡上建立了索引,那麼當進行select age from employee where age < 20的查詢時,在索引的葉子節點上,已經包含了age資訊,不會再次進行回表查詢。

8 聯合索引是什麼?為什麼需要注意聯合索引中的順序?

MySQL可以使用多個欄位同時建立一個索引,叫做聯合索引。在聯合索引中,如果想要命中索引,需要按照建立索引時的欄位順序挨個使用,否則無法命中索引。

具體原因為:

MySQL使用索引時需要索引有序,假設現在建立了"name,age,school"的聯合索引,那麼索引的排序為: 先按照name排序,如果name相同,則按照age排序,如果age的值也相等,則按照school進行排序。

當進行查詢時,此時索引僅僅按照name嚴格有序,因此必須首先使用name欄位進行等值查詢,之後對於匹配到的列而言,其按照age欄位嚴格有序,此時可以使用age欄位用做索引查詢,以此類推。因此在建立聯合索引的時候應該注意索引列的順序,一般情況下,將查詢需求頻繁或者欄位選擇性高的列放在前面。此外可以根據特例的查詢或者表結構進行單獨的調整。