圖解mysql索引---歷史最詳細、最清楚的講解

我們先來列一個提綱,從以下幾個方面介紹mysql索引

  • 1、索引的本質
  • 2、索引結構及其詳細解讀(二叉樹、紅黑樹、HASH、B-Tree、B+Tree)
  • 3、非聚集索引(MyISAM)、聚集索引(InnoDB
  • 4、常見問題

一、索引的本質

  1. 索引是幫助mysql高效獲取數據的排好序的數據結構
  2. 索引存儲在文件裏
  3. 索引結構
  •            二叉樹
  •            Hash
  •            B樹

注意:索引起的作用是:排好序的快速查找數據結構!索引會影響where後面的查找,和order by 後面的排序。

關係型數據庫的數據是存儲在磁盤上面,且是不均勻存在不同的扇區上的,查詢內容需要磁頭在磁盤去尋找,找一次就是一次磁盤I/O。

  • 磁盤存取原理
  1. 尋道時間(速度慢,費時)
  2. 旋轉時間(速度較快)

二、索引結構及其詳細解讀(二叉樹、紅黑樹、HASH、B-Tree、B+Tree)

接下來我們根據一張圖來講解幾種索引

1、二叉樹:右邊的子元素大於父元素,左邊的子元素小於父元素。如下圖

從上圖可以看到,執行where col1=0007時,得經過7次磁盤IO

現在通過二叉樹算法給col2建立索引,執行where col2=89時,第一次查34,然後再查89,經過兩次磁盤io查到了。

2、紅黑樹(二叉平衡樹):

從上圖可以看到,執行where col1=0007時,得經過4次磁盤I/O,很明顯比二叉樹少了很多次磁盤I/O操作

總結:二叉樹和紅黑樹的缺點就是:樹的高度太高

存儲1000萬條數據,設樹的高度爲n,則,則n=23.253497。

3、Hash索引:

基於哈希表實現,只有精確匹配索引所有列的查詢纔有效,對於每一行數據,存儲引擎都會對所有的索引列計算一個哈希碼(hash code),並且Hash索引將所有的哈希碼存儲在索引中,同時在索引表中保存指向每個數據行的指針。

4、B-Tree:多叉平衡樹

  • 度(Degree)-節點的數據存儲個數

  • 葉節點具有相同的深度

  • 葉節點的指針爲空

  • 節點中的數據key從左到右遞增排列

B-Tree缺點

現在要查找where col>20,則困難重重,得找好多次,下面我們來看一下B樹變種B+樹

5、B+Tree(B-Tree變種):

  • 非葉子節點不存儲data,只存儲key,可以增大度

  • 葉子節點不存儲指針

  • 順序訪問指針,提高區間訪問的性能

從上圖可以看到找到where col>20的數據,根據指針一次就能找出來

B+Tree索引的性能分析

  1. 一次使用磁盤I/O次數評價索引結構的優劣
  2. 預讀:磁盤一般會順序向後讀取一定長度的數據(頁的整數倍)放入內存
  3. 局部性原理:當一個數據被用到時,其附近改的數據也通常馬上被使用
  4. B+Tree節點的大小設爲等於一個頁,每次新建節點直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,就實現了一個節點的載入只需一個I/O
  5. B+Tree的度d一般不會超過100,因此h非常小(一般爲1到3之間)
  6. 一般操作系統的最小存儲單元爲頁。1頁大小爲4K
  7. 查看mysql文件頁大小(16K): SHOW GLOBAL STATUS LIKE ‘Innodb_page_size’;

三、非聚集索引(MyISAM)、聚集索引(InnoDB

1、MyISAM索引實現非聚集

首先我們先來看一下MyISAM引擎在磁盤裏是如何存在的

MyISAM索引文件和數據文件是分離的

MyISAM引擎使用B+Tree作爲索引結構,葉節點的data域存放的是數據記錄的地址。如圖:

這裏設表一共有三列,假設我們以Col1爲主鍵,則上圖是一個MyISAM表的主索引(Primary key)示意。可以看出MyISAM的索引文件僅僅保存數據記錄的地址。在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是唯一的,而輔助索引的key可以重複。如果我們在Col2上建立一個輔助索引,則此索引的結構如下圖所示:

如上圖,同樣也是一棵B+Tree,data域保存數據記錄的地址。因此,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,則取出其data域的值,然後以data域的值爲地址,讀取相應數據記錄。 
MyISAM的索引方式也叫做“非聚集”的,之所以這麼稱呼是爲了與InnoDB的聚集索引區分。

2、InnoDB索引實現聚集

  1. 表數據文件本身就是按B+Tree組織的一個索引結構文件
  2. 聚集索引-葉節點包含了完整的數據記錄
  3. 爲什麼InnoDB表必須有主鍵,並且推薦使用整型的自增主鍵?
  4. 爲什麼非主鍵索引結構葉子節點存儲的是主鍵值?(一致性和節省存儲空間)

先看一下InnoDB引擎在磁盤裏是如何存在的

雖然InnoDB也使用B+Tree作爲索引結構,但具體實現方式卻與MyISAM截然不同。

第一個重大區別是InnoDB的數據文件本身就是索引文件。從上文知道,MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。

上圖是InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。

第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作爲data域。例如,下圖爲定義在Col3上的一個輔助索引:

這裏以英文字符的ASCII碼作爲比較準則。聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。

四、常見問題

1、爲什麼mysql頁文件默認16k?

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

那麼一顆高度爲2的B+樹能存儲的數據爲:1170*16=18720條,一顆高度爲3的B+樹能存儲的數據爲:1170*1170*16=21902400(千萬級條)

2、爲什麼索引結構默認使用B-Tree,而不是hash,二叉樹,紅黑樹?

hash:雖然可以快速定位,但是沒有順序,IO複雜度高。

二叉樹:樹的高度不均勻,不能自平衡,查找效率跟數據有關(樹的高度),並且IO代價高。

紅黑樹:樹的高度隨着數據量增加而增加,IO代價高。

3、爲什麼官方建議使用自增長主鍵作爲索引?

結合B+Tree的特點,自增主鍵是連續的,在插入過程中儘量減少頁分裂,即使要進行頁分裂,也只會分裂很少一部分。並且能減少數據的移動,每次插入都是插入到最後。總之就是減少分裂和移動的頻率。

插入連續的數據:

 

插入非連續的數據

 

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