mysql的索引innodb和myisam, 以及B+Tree和B-Tree詳解

一. mysql的索引

mysql常用的索引有以下幾種:

  1. hash索引

    hash索引通過hash值來匹配對應的數據,類似鍵值對的形式,查找的時候可以精準一次定位,但是對於範圍查詢,排序效率不高,並且hash索引不能避免全表掃描,因爲hash值並不能完全保證一個hash值匹配一個數據(hash衝突),還是需要比對實際數據

  2. btree索引

    MySQL裏默認和最常用的索引類型,利用二分查找的思想構建的數據結構

  3. 全文索引

    myisam引擎支持全文索引,innodb在mysql5.6以後也支持全文索引,不過基於mysql很少存儲text大文本數據,全文檢索也被es替代

二. 二叉樹到B-Tree和B+Tree

2.1 二叉樹到平衡二叉樹

二叉樹是一種基礎的樹結構,它通常由一個根節點和衍生的分支組成.它的特點是:

  1. 每個節點都最多隻有兩個子節點(分支)

二叉樹只是一個樹結構,在實際應用中還有一種特殊的二叉樹,叫二叉查找樹.

它在二叉樹的基礎上,多了一個特點,左邊的節點都比右邊的節點小

在這裏插入圖片描述

但是可能會出現特殊情況,就會從樹狀結構變成鏈表結構,查詢效率大打折扣.結構如下

在這裏插入圖片描述
爲了解決這個問題,又出現了平衡二叉樹.

平衡二叉樹的特點就是,左右兩個分支的高度相差不會超過1.

如果在一個分支加一個節點,導致兩邊高度超過1了,平衡二叉樹會做一個旋轉操作進行平衡.

左旋如動圖:

在這裏插入圖片描述

右旋如動圖:

在這裏插入圖片描述

2.2 從平衡二叉樹到B-Tree

B-Tree是基於平衡二叉樹優化而來,且Btree是一種是爲磁盤等外存儲設備設計的一種平衡查找樹.所以先了解一下磁盤的存儲結構

2.2.1 硬盤的存儲

硬盤是一個由很多個盤片組成的結構,上下兩面都可以讀寫

在這裏插入圖片描述

圖中的一圈圈灰色同心圓爲一條條磁道,從圓心向外畫直線,可以將磁道劃分爲若干個弧段,每個磁道上一個弧段被稱之爲一個扇區(圖踐綠色部分)。扇區是磁盤的最小組成單元,通常是512字節。

在這裏插入圖片描述

當需要從硬盤讀取數據的時候,系統會將數據的存儲地址給磁盤,磁頭需要移動到相應的磁道上,這個過程叫尋道, 然後磁盤旋轉將目標扇區旋轉到磁頭下,這個耗費的時間叫旋轉時間.

根據局部性原理,系統會認爲,當某個數據被用到時,它附近的數據也會被使用. 同時也爲了減少讀取的io次數,避免多次尋道和旋轉磁盤, 磁盤往往不是嚴格按需讀取,而是每次都會預讀一部分數據.

預讀的長度一般爲頁,通常大小是4k.

2.2.2 B-Tree的特性

在這裏插入圖片描述
一個m階的B-Tree滿足以下特點:

  1. 每一個節點最多有 m 個子節點
  2. 每一個非葉子節點(除根節點)最少有 ⌈m/2⌉ 個子節點
  3. k 個子節點的非葉子節點擁有 k − 1 個關鍵字
  4. 非葉子節點都是由關鍵字,指針和數據組成,指針指向子節點
  5. 每個節點的關鍵字key的數量是指針數量n-1,可以理解爲指針在關鍵字的兩側
  6. 所有葉子節點所處的高度一樣
  7. 關鍵字只會在樹中出現一次
  8. 關鍵字從左到右遞增

2.2.3 B+Tree的特性

B+Tree是基於B-Tree的優化.

在這裏插入圖片描述
一個m階的B+Tree滿足以下特點:

  1. 每一個節點最多有 m 個子節點
  2. 每一個非葉子節點(除根節點)最少有 ⌈m/2⌉ 個子節點
  3. 所有葉子節點所處的高度一樣
  4. 所有關鍵字,都會在葉子節點出現
  5. 非葉子節點只存儲關鍵字key和指針,只有葉子節點保存數據
  6. 關鍵字從左到右遞增

區別在於:

  1. B-Tree的關鍵字分佈在各個節點,不會重複出現. 而B+Tree的關鍵字都會出現在葉子節點
  2. B+Tree的非葉子節點不會保存數據信息. 數據信息都在葉子節點中
  3. B+Tree的葉子節點從左到右順序排列,並且存在指針連接,是一個鏈表結構

2.3 B樹添加數據,刪除數據

2.3.1 添加

在這裏插入圖片描述g)

2.3.2 刪除

在這裏插入圖片描述
動圖觀看實驗網址
可以自己試試添加節點和刪除節點
在這裏插入圖片描述

這也就解釋了爲什麼主鍵需要自增,因爲主鍵的順序和數據存儲的順序是一致的,如果主鍵不是遞增順序的, 會導致插入數據的時候造成B+Tree的節點的分裂和移動,並且因爲分頁形成碎片,浪費資源

2.3 爲什麼B+Tree適合查詢硬盤存儲數據

由上面硬盤結構可知,讀取數據所耗費的時間,絕大多數花在硬盤io上,而內存中的處理則快很多.那麼提高查詢的效率,就是減少磁盤io的次數. 如上圖的主鍵爲29的記錄,需要三次io可以定位

我們也可以看出:磁盤的IO次數,和樹的高度成正相關,也就是說,降低樹的高度,就可以減少io次數.

上面我們知道硬盤有頁的概念,InnoDB存儲引擎也有頁的概念,默認每個頁的大小爲16KB,在MySQL中可通過如下命令查看頁的大小:

mysql> show variables like 'innodb_page_size';

在這裏插入圖片描述

我們假設一行的數據是1K,那我們一頁的數據,就能存儲16行數據,也就是一個葉節點可以存儲16條記錄;再來看非葉節點,假設ID是bigint類型,那麼長度爲8B,指針大小在InnoDB源碼中爲64(6B),一共就是14B,那麼一頁裏面就可以存儲16K/14=1170個(主鍵+指針)

那麼一棵高度爲2的B+樹能存儲的數據爲:

1170 * 16=18720條,一棵高度爲3的B+樹可以存儲1170 * 1170 * 16 = 21902400(兩千萬條)

也就是說,兩千萬級別的數據,根據主鍵查詢最多都只需要三次IO操作就可以找到記錄.

2.4 爲什麼B+Tree比B-Tree更好

  1. 因爲B+Tree非葉子節點不存儲數據,而是隻存儲關鍵字和指針,所以每個節點能保存的關鍵字和指針比B-Tree更多,所以子節點更多,同樣的數據量樹的高度更矮,磁盤IO操作更少
  2. B+Tree所有數據都在葉子節點,且葉子節點之間是排好序的鏈表,範圍查詢,排序能力比B-Tree更強

三. 索引結構

3.1 聚簇索引(聚集索引)和非聚簇索引(輔助索引,二級索引)

聚簇索引和非聚簇索引並不是一種類似非空索引,主鍵索引的索引類型,而是一種數據存儲方式

簡單的說,聚簇索引就是索引和數據存儲在一起,在B+Tree中,表示都一個葉子節點上關鍵字和它代表的數據行存儲在一起

非聚簇索引則是相反. 索引和真正的數據行是分開的. 在B+Tree中,葉子節點上存的是主鍵id

由於聚簇索引是將數據跟索引結構放到一塊,因此一個表僅有一個聚簇索引

聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB 會選擇一個唯一的非空索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵來作爲聚簇索引.

除了聚簇索引以外,我們建的其他普通索引,都是二級索引,或者叫輔助索引.像複合索引、前綴索引、唯一索引

  • 聚簇索引

在這裏插入圖片描述

  • 輔助索引

    輔助索引最後葉子節點上保存的不是數據行,而是聚簇索引的id(通常就是主鍵id),所以如果通過輔助索引查詢數據, 需要遍歷兩次B+Tree

在這裏插入圖片描述

三. InnoDb和MyISAM

在mysql5.5.5之前,默認引擎是MyISAM,之後換成了InnoDb

Before MySQL 5.5.5, MyISAM is the default storage engine. (The default was changed to InnoDB in MySQL 5.5.5.) MyISAM is based on the older (and no longer available) ISAM storage engine but has many useful extensions.

在myisam中,不管是不是主鍵,還是普通索引,葉子節點上保存的都是數據的物理磁盤的引用地址,當查詢到這個引用地址,就可以將這份數據加載到內存.

在這裏插入圖片描述

而在innodb中,使用的就是上面的聚簇索引, 在主鍵(或者系統默認的隱式一個主鍵索引)的葉子節點上, 保存的是數據行的真實信息. 其他索引(輔助索引)的葉子節點都是這個主鍵索引的關鍵字的值.

比如在主鍵以外的name字段建立索引,innodb會在輔助索引找到ID索引的值,再通過ID索引獲取最終的數據.

這樣看起來innnodb似乎比myisam效率更低,但是如果用主鍵查詢的話,在葉子節點查到數據的同時也就將數據讀取到內存中了,無需根據物理地址再進行一次磁盤讀取操作. 而且輔助索引都是儲存的主鍵的id,所以即便數據遷移了,只要id不變,輔助索引也無需進行變更

在這裏插入圖片描述

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