關於Mysql索引你必定要知道的(上)

關於Mysql索引你必定要知道的

導圖

索引模型

Hash

簡介

Hash索引是MEMORY引擎默認使用的索引結構,也只有MEMORY引擎能夠顯式使用Hash索引,實際上就是HashTable,key-value結構。同時也是用拉鍊法解決hash衝突,這裏不展開討論。html

結構

iShot2021-07-04 11.58.14.png

這裏須要注意的是HashTable的Value裏面並非直接存儲的單行數據而是存的是指針。mysql

特色

  1. 在哈希索引中沒有存索引字段的信息,因此並不能經過索引值來減小讀取行數
  2. 哈希索引不是有序的,因此並不能作排序
  3. 哈希因此不支持索引匹配查找,好比說b+樹索引可以使用最左匹配原則去使用聯合索引,而哈希索引不能。也就是說在數據列(A,B)上創建哈希索引,若是查詢只有數據列A,則沒法使用該索引。
  4. 哈希索引進行檢索效率很是高,基本上一次檢索就能夠找到數據,從檢索次數上來講比B+樹索引要少得多
  5. 只支持等值查詢,範圍查詢不支持
  6. 當哈希碰撞過多的時候,索引的維護代價很高

B樹

簡介

若是咱們要了解B+樹,就必定要先了解B樹,B樹是爲磁盤等直接存儲的輔助存儲設備而設計的一種平衡搜索樹,它的節點能夠存儲多個關鍵字,而且它是一個多叉樹,一個B樹知足如下條件:算法

先解釋幾個詞:sql

  • 關鍵字:每一個節點存儲的數據
  • x:每一個節點存儲關鍵字的數量
  • m:樹的高度

定義:數據庫

  1. 是一顆有根樹
  2. 每一個節點包含x+1個指向孩子節點的指針
  3. 每一個節點的所存儲的關鍵字以非降序排列,每一個數據的左子樹中的全部數據都小於它,而右子樹中的全部數據都大於它。
  4. 每一個葉節點都有相同的深度,即樹的高度,也能夠說成葉結點都位於同一層
  5. 每一個節點至多有m-1個數據
  6. 根節點最少能夠只有1個數據

數據結構

如圖這是一個3階B樹 iShot2021-07-04 11.59.08.pngmarkdown

插入刪除

B樹的插入主要涉及三個步驟,查詢、插入、分裂。數據結構

  • 查詢:這裏指的是找到插入位置,這裏的查找和二叉搜索樹的查找相似
  • 插入:關鍵字插入過程
  • 分裂:爲了保持B樹的結構,當節點關鍵字數量達到閾值,就會產生分裂動做,中間關鍵字提高到父節點,其餘節點生成兩棵新子樹

B樹的刪除其實和插入很是類似,只是更加複雜一點,由於刪除能夠從任意節點刪除,而並不是只能從葉子節點刪除。因此就涉及到刪除後保持結構定義的過程。這裏就再也不贅述刪除具體的流程,比較複雜。建議你們去看一下《算法導論》286頁,有詳細的描述。oop

動畫

這裏能夠看到 Max. Degree = 3 表示是一個三階B樹,因此他的關鍵字最多隻能有三個。性能

  1. 當咱們插入1,樹是空的,因此直接插入。
  2. 插入3,因爲3大於1,而且當前節點關鍵字小於3,因此放在同一個節點1後面的位置.
  3. 插入5,5大於3因此在3後面,當前節點的關鍵字=3,觸發分裂,中間關鍵字3向上升入根節點,1,5生成兩個新子樹
  4. 插入4,4大於根節點3,因此往右邊查找,小於5,而且節點關鍵字數小於3
  5. 刪除1,找到1的位置,刪除,發現左子樹爲空了,不知足定義,004關鍵字上升成爲根結點,003,005分別爲左右節點。

這時候若是咱們再插入1,就會發現,結構並不會恢復成以前的樣子。 動畫

查詢

其實從剛剛的插入刪除的演示中就已經能夠看出查詢的過程,搜索一顆B樹和搜索一顆二叉搜索樹相似,不一樣的就在於每一個節點的分支選擇是多叉的,而不必定是二叉。

爲何B樹(N叉)適合作索引

爲了探究這個問題咱們首先應該瞭解幾個知識

  • 索引的存儲

索引就是一種數據結構,須要存儲,而且索引也不僅僅在內存中,須要存儲到磁盤中。

  • 影響數據庫查詢速度的因素

在我以前的博文中提到過,實際上數據庫查詢數據是先查主存,若是不存在,纔去磁盤中查詢,而後帶到主存裏來。這裏在磁盤查詢的過程當中會涉及到磁盤的io,實際上若是不考慮從主存中查詢,最影響數據庫查詢速度的就是磁盤IO,所以儘可能減小磁盤IO就能夠顯著的提高數據的查詢速度。

  • 預讀機制

傳統的磁盤讀取依靠的是機械運動,IO的耗時就分爲尋道時間、旋轉延遲、傳輸時間三個部分。**SSD則不一樣。**爲了減小io的消耗,採用來預讀的機制。當訪問一個地址數據的時候,與其相鄰的數據很快也會被訪問到。每次磁盤IO讀取的數據咱們稱之爲一頁(page)。一頁的大小與操做系統有關,通常爲4k或者8k。這也就意味着讀取一頁內數據的時候,實際上發生了一次磁盤IO。

經過上面幾點,咱們就能夠知道,索引會寫盤,查詢索引的過程就是查詢節點的過程若是不在內存中就會去查找磁盤,產生磁盤IO,那麼索引的查詢速度大部分就取決於每次查詢須要訪問的數據頁。咱們能夠假設一棵 100 萬節點的平衡二叉樹,樹高 20。一次查詢可能須要訪問 20 個數據塊。而若是使用b樹的話就取決於咱們N叉樹的N的大小。固然,這裏B+樹也是同理的。

B+樹

簡介

B+樹其實就是B樹和順序索引訪問方法演化而來的,在這裏就不贅述B樹和B+樹的區別了,你們只要知道B樹的每一個結點都存儲了key和data,B+樹的data存儲在葉子節點上。

結構

B+樹其實就是B樹的變體,和B樹很類似。如圖是一個三階B+樹。

插入和刪除

從圖中咱們能夠和清楚的看到,實際上B+樹的插入和刪除的過程和B樹基本一致,惟一區別是,B+樹經過一個雙向鏈表把葉子節點連接起來,在維護樹的時候一樣須要維護這個雙向鏈表,這裏也不仔細去說詳細的插入刪除的算法。詳見《Mysql技術內幕 InnoDB存儲引擎》 P202

查詢

查詢過程其實也是接近的,區別只是B+樹的節點沒有存儲data,因此其實是查到鏈表中。

區別

  1. B+樹改進了B樹, 讓非葉子結點只做索引使用, 去掉了其中指向data record的指針, 使得每一個結點中可以存放更多的key, 所以能有更大的扇出數。
  2. 葉子結點使用鏈表形式鏈接。

非葉子節點不存儲數據就意味着存放一樣多的key, 樹的層高能進一步被壓縮, 使得檢索的時間更短。而且葉子結點是鏈表形式,能更快的進行順序遍歷。

聚簇索引(clustered index)

也就是主鍵索引,葉子節點存儲的是整行的數據,而且數據也是依據主鍵索引進行排序,主鍵索引一張表只能有一個也是由於數據只能按照一個索引進行排序。聚簇索引附帶惟一性約束。

非聚簇索引(secondary index)

也叫輔助索引,葉子節點並不存放整行數據,而是存儲主鍵的值。要查找到完整數據須要回表。

惟一索引

用來確保表中沒有兩個數據行具備徹底相同的鍵值通常咱們使用它來幫助維護數據完整性。同時須要注意惟一性約束不等於惟一索引。

非惟一索引

普通索引,用來輔助查詢,不具有惟一性約束。

頁分裂

索引按照順序遞增(不必定要連續,只要是遞增就行),索引緊湊;隨機插入爲了保證索引的順序行可能會形成索引的數據頁分裂。數據頁的分裂就產生數據空洞。分裂過程不只影響性能還會影響空間使用率,由於本來一個數據頁的數據,分紅了兩個數據頁。 固然有分裂就有合併。當相鄰兩個頁因爲刪除了數據,利用率很低以後,會將數據頁作合併。合併的過程,能夠認爲是分裂過程的逆過程。

這裏引用一張《Mysql 45講》中的圖

回表

非聚簇索引查詢到主鍵,回到聚簇索引搜索的過程,咱們稱爲回表。

覆蓋索引

覆蓋索引並非一種索引類型,而是從非聚簇索引中就能夠查詢到的結果不用,再去回表。這種操做能夠的好處是,非聚簇索引只存儲索引值,並無整行的數據,故其大小遠小於聚簇索引,能夠減小大量的io操做,因此咱們常說不要用select *。

聯合索引

聯合索引是指對錶上的多個列進行索引,聯合索引也是一棵B+樹,不一樣的是聯合索引的鍵值數量不是1,而是大於等於2。 這裏須要注意的是聯合索引的結構 聯合索引的全部索引列都出如今索引樹上,並依次比較三列的大小進行排序。

做者水平有限,如有錯誤遺漏,請指出。

參考文章

1.MySQL索引背後的數據結構及算法原理

2.stackoverflow

3.深刻理解數據庫索引採用B樹和B+樹的緣由

4.MySQL實戰45講

5.MySQL技術內幕 InnoDB存儲引擎 第2版

相關文章
相關標籤/搜索