索引爲什麼選擇B+Tree

索引爲什麼選擇B+Tree

一、簡介

  本文主要解答索引爲什麼選擇B+Tree,而不使用哈希、二叉搜索樹、二叉平衡樹、紅黑樹、B Tree。

  索引選擇哪種數據結構,主要從兩方面來考慮:

  1. 數據的存儲效率;
  2. 數據的查詢效率。

  本文通過講解每種數據結構在這兩方面的效率,以及其他方面的優缺點,來回答爲什麼選擇B+Tree。

二、哈希

  哈希數據結構如圖所示:

  哈希數據結構的哈希值是將鍵通過某種哈希算法轉化而來,哈希算法是多種對樣的,也可以自定義的。

  優點:只要知道“鍵”,立馬通過哈希算法得到哈希值,從而找到目標數據,查詢速度快。

  缺點如下:

  • 爲了防止哈希值衝突,往往需要複雜化的哈希算法;
  • 查詢數據時,需要將所有數據文件添加到內存中,若數據量大時,耗費內存空間;
  • 哈希數據結構無法進行範圍查找。實際工作中,往往是範圍查找。

總結:哈希數據結構存儲效率正常,對於定值查詢效率高,但不支持範圍查詢。

三、樹

  樹的結構爲一個節點可以有多個葉節點。如圖所示:

  缺點:查詢數據時,需要對數一層一層的查找,效率低。

四、二叉樹

  二叉樹在樹的結構上進行了優化,爲了方便管理,規定每個節點最多只能有兩個子節點。(這是爲了進一步優化爲二叉搜索樹、二叉平衡樹等)

  缺點:查詢數據時,需要對數一層一層的查找,效率低。

五、二叉搜索樹

  在二叉樹的基礎上,二叉搜索樹作了進一步規定:

  • 左子樹必須小於根節點;
  • 右子樹必須大於根節點。

  優點:根據二叉搜索樹規定的節點與左右節點的關係,查詢數據時,可使用二分查找,查詢效率大大提升。

  缺點:存儲數據時,如果數據是有序的,並按順序存儲時,會導致某一字數過長,如,順序存儲1、2、3、4、5,如圖所示:

  由圖可見,對於這種特殊插入情況,會導致二叉樹搜索樹失去樹的結構,稱爲了一種鏈式結構,那麼就會導致查詢數據時效率低。

六、二叉平衡樹

  針對二叉搜索樹的缺點,二叉平衡樹在二叉樹的基礎上,加入了左右旋,以滿足最長子樹與最短子樹相差不超過1,同時也滿足二分查找。

  順序插入1、2、3時,二叉平衡樹右旋,如圖所示:

  順序插入4、5時,二叉平衡樹右旋,最終樹如圖所示:

  優點:查詢數據時,可使用二分查找提高查詢效率。

  缺點:

  • 左右旋頻繁操作,導致存儲數據效率變低;
  • 隨着存儲數據的增多,樹的層次加深,那麼訪問數據的IO次數也增加,導致查詢數據效率逐漸變低。

七、紅黑樹

  針對二叉平衡樹的左右旋操作,紅黑樹進行了改進,目的在於,犧牲一點存儲效率,以提升查詢效率。

  紅黑樹規定:

  • 最長子樹不超過最短子樹的兩倍即可。(也就減少了左右旋的次數)

  紅黑變色規則:

  1. 插入的每個節點必須是紅色;
  2. 每一條路徑不允許有兩個連續的紅色節點;
  3. 任何一個分支上,黑色節點個數必須相等。

  順序插入1、2、3、4、5、6時,紅黑樹如圖所示:

  優點:相對於二叉平衡樹的插入效率要高,因爲左右旋的次數降低。

  缺點:隨着存儲數據的增多,樹的層次加深,那麼訪問數據的IO次數也增加,導致查詢數據效率逐漸變低。

八、B Tree

  基於紅黑樹的缺點,要想降低樹的深度,那麼要打破每個節點只能存儲兩個子節點的限制。

  允許每個節點有多個子節點,B Tree如圖所示:

  優點:相對於紅黑樹,在相同數據量的條件下,B Tree的深度較小。

  缺點:

  • 隨着存儲數量的增加,深度還是會加深,查詢效率低;
  • 葉子節點沒有雙向指針,不能範圍查找。

九、B+Tree

  基於B Tree深度還是會加深的缺點,試圖讓一個節點存儲更對的“鍵”,一個辦法就是將節點中的數據data去掉,這樣一個節點存儲“鍵”的個數增加,所以深度就會降低。

  基於B Tree不能範圍查找的缺點,在葉子節點中,增加雙向鏈表,就可以進行範圍查找。

  經過從哈希數據結構到B+Tree數據結構的講解,理解了每一種樹要解決的問題,現在很容易理解索引選擇B+Tree的原因了吧。

  注意:

  • InnoDB是通過B+Tree結構對主鍵創建索引的,然後葉子接機點中存儲記錄,如果沒有主鍵,那麼會選擇唯一鍵,如果沒有唯一鍵,那麼會生成一個6位的row_id作爲主鍵;
  • 如果創建索引的鍵是其他字段,那麼在葉子節點中存儲的是該記錄的主鍵,然後再通過主鍵索引找到對應的記錄,叫做回表。

十、InnoDB一棵B+樹可以存放兩千萬行數據

  InnoDB存儲引擎的最小儲存單元——頁(Page),一個頁的大小是16K。假設一行數據的大小是1k,那麼一個頁可以存放16行這樣的數據。

  假設主鍵ID爲bigint類型,長度爲8字節,而指針大小在InnoDB源碼中設置爲6字節,這樣一共14字節,我們一個頁中能存放多少這樣的單元,其實就代表有多少指針,即16384/14=1170。

  可以算出一個高度爲3的B+Tree可以存放**:**1170 * 1170 * 16=21902400條這樣的記錄。

十一、InnoDB與MyISAM中的B+Tree區別

  InnoDB中B+Tree的葉子節點存儲了數據,而MyISAM中B+Tree的葉子節點存儲了數據的地址。

  InnoDB的B+Tree:

  MyISAM的B+Tree:

十二、索引的相關問題

12.1、聚集索引、非聚集索引

  聚集索引:在B+Tree中,葉子節點存儲了整行數據的索引。在InnoDB中,只有主鍵索引是聚集索引,當沒有主鍵時,會選取唯一鍵;當沒有唯一鍵時,會添加6位row_id作爲主鍵。其他索引都是非聚集索引。

  非聚集索引:在B+Tree中,葉子節點沒有存儲整行數據的索引。比如MyISAM中B+Tree葉子節點存儲的是數據的地址。

12.2、回表

  在InnoDB中,除主鍵索引外,比如組合索引,葉子節點存儲的是數據的主鍵信息。當通過組合索引查詢到對應的主鍵信息後,再到主鍵索引中查詢整行數據,該過程稱爲回表。

12.3、覆蓋索引

  在InnoDB中,使用索引查詢到對應數據的主鍵信息,該主鍵正是本次查詢的數據,可以直接返回,而不用訪問回表,該過程稱爲覆蓋索引。

12.4、索引下推

  當有組合索引name、age時,通過該索引查詢會先根據name得到主鍵並回表,回表會增加查詢的步驟、降低查詢效率,回到主鍵索引再查詢age。

  而使用索引下推後,就會優先在索引上進行查詢過濾。

使用explain查詢會發現:

  • 當Extra的值爲Using index condition; 說明查詢的字段全部在索引上完成了過濾操作,回表時會根據主鍵直接得到對應的行數據。
  • 當Extra的值爲Using where時,可能查詢字段沒有設置索引,這時會直接在主鍵索引上查詢,效率低下。
  • 當Extra的值爲Using index condition; Using where時,說明查詢的一部分部分字段有索引,另一部分沒有索引,當有索引的字段完成查詢時回表,並不會立馬返回數據,而是還要再全表查詢那些沒有索引的字段。
    對應的行數據。
  • 當Extra的值爲Using where時,可能查詢字段沒有設置索引,這時會直接在主鍵索引上查詢,效率低下。
  • 當Extra的值爲Using index condition; Using where時,說明查詢的一部分部分字段有索引,另一部分沒有索引,當有索引的字段完成查詢時回表,並不會立馬返回數據,而是還要再全表查詢那些沒有索引的字段。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章