學習MySql索引的數據結構,只需這一篇就夠了

什麼是索引呢?

百度百科上的解釋爲: 索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。

簡單來說:字典目錄就是整個字典的索引,也就相當於目錄,字典目錄的作用是快速定位某一個漢字,而索引的作用是快速定位所需數據
在這裏插入圖片描述

如何創建索引呢?

創建索引需要兩個條件,這就是:我要給誰–以什麼實現方式–創建什麼類型的索引
1. 給誰:就是給那個字段,這裏可以是一個字段,也可以是多個字段;
2. 實現方式:就是索引的數據結構,可以是BTREE、HASH;
3. 類型:就是索引的類型,innoDB中一共支持四種索引類型,分別是普通索引、唯一索引、主鍵索引、全文索引。

創建索引的字段:可以是一個字段,也可以是多個字段,在多個字段上使用時需要滿足最左匹配原則。

索引方式:

  1. BTREE:是 MySQL 默認的索引方式 。
  2. HASH:以 KV 的形式檢索數據,它會根據索引字段生成哈希碼和指針,指針指向數據。【相比於BTREE結構,HASH中的數據不能按照排序來存儲,也不支持範圍查詢】

索引的類型:

  1. 普通索引(Normal):也叫非唯一索引,沒有任何限制。
  2. 唯一索引(Unique):唯一索引要求索引所在的列不能重複。
  3. 主鍵索引(Primary):是特殊的唯一索引,相比於唯一索引增加了一個限制條件,要求所在的列不能爲null。
  4. 全文索引(Fulltext):用於搜索很長一篇文章的時候,效果最好。
    Fulltext的使用可參考:Fulltext的使用

爲什麼最終將樹形索引的數據類型定義爲B+樹呢?

給你無序的數字,讓你找出其中的某個數字,那隻能一個個遍歷了,對應的結構只能是HASH

但當這一串數字爲有序的呢?大家第一反應一定是通過二分查找的方式檢索,每次比較可以捨去一半的數據,那麼對應到數據結構上應該使用什麼數據結構來存儲索引呢?答案可想而知,是平衡二叉樹

平衡二叉樹:從樹根開始比較,每次可以捨去一半的數據,但同時也就說明,數據量每擴大一倍需要多比較一次。由於在當前比較之前,無法確定之後是走左子樹還是走右子樹,也就說明每一次比較伴隨着一次數據讀取。而IO是及其消耗性能的,那怎麼辦呢?大家可以想一下操作系統一次IO讀取的數據大小是多少呢?對,是4k,而每次讀取一個節點的節點大小遠遠不足4k,那麼我們在每一個節點處多存儲一些數據來減少磁盤的IO是不是更好一些呢?
平衡二叉樹示例

多路平衡二叉樹【B Tree】:每一個節點不再只存儲一個數據,可以同時存儲多個數據,儘量保證每一個節點的數據量的大小接近4k,這樣就可以通過最少的IO次數來提高檢索數據的效率。但是這隻解決的等值比較的方式,那麼範圍查詢如何通過索引來檢索呢?可見B Tree也不是理想的數據結構,那麼如何才能做到範圍查詢呢?線性有序的一串數字我們才能夠更方便的進行範圍查詢,那麼可不可以將BTree結構和線性有序的結構進行組合呢?
在這裏插入圖片描述
B+Tree:從B Tree中可以看出,數據大部分集中在葉子節點上,那我們將所有分支節點的數據複製一份到葉子節點上,那麼從左向右看葉子節點就會發現,葉子節點存儲了所有的數據,並且從左到右看上去是一個線性有序的序列,爲了讓程序也像人眼一樣“”,那麼上一個葉子節點的末尾存儲下一個葉子節點的地址即可,也就構成了B+Tree的結構。
在這裏插入圖片描述
在理論上,三層B+Tree可以存儲上百萬條數據,也就是我們僅需要進行3次IO操作就可以快速定位到所需的數據。

有的人可能回想,那你每個節點存放這麼多數據,我在每個葉子節點上不還是需要一個一個遍歷比較嗎,對比於沒有索引的情況下,性能會有很大的提升嗎?

對於這個問題,可以做一個假設:假設每個節點上存放一千條數據,樹的高度一共爲三層。由於每個節點有一千條數據,也就是說每個非葉子節點有一千個子節點,樹的高度爲3層的話一共可以儲存1000 * 1000 * 1000=10w條數據,也就是說使用索引的情況下平均需要遍歷5w次,而使用索引只需要遍歷3 * 1000 =3000次,性能的提升是很明顯的。

瞭解了索引數據結構的演變,那麼MySQL中的數據結構是什麼樣子的呢?

MySQL中常用的存儲引擎是MyISAM和InnoDB,我們在討論兩個常用存儲引擎的索引結構時先看一下數據和索引的存放方式,我新建了兩張表分別使用了MyISAM和InnoDB兩個存儲引擎,並建立了主鍵索引,數據以及索引的存儲如圖:在這裏插入圖片描述

.frm後綴文件定義了表的結構,MyISAM和InnoDB兩者類似。

MyISAM:中除了.frm還有.MYD和.MYI

  1. .MYD(MyISAM Data),用於存放表數據
  2. .MYI(MyISAM Index),用於存放索引,索引的葉子節點存放的是數據的內存地址
    也就說明MyISAM索引和數據是兩個獨立的文件

InnoDB:中除了.frm還有.ibd
在InnoDB中數據的存儲和索引的存儲均在.ibd中,InnoDB中是以主鍵爲索引來組織數據存儲的,也就是所有數據都存在於主鍵的葉子節點上(如果沒有顯式創建主鍵,InnoDB會創建一個默認的主鍵索引),那麼我如果給其他字段上創建普通索引是如何存儲的呢?
如果給其他字段創建普通索引,子節點的key存放的是當前字段的值,而葉子節點的value存放的是該條數據主鍵的值(一般情況下爲id)
在這裏插入圖片描述

總結有以下幾點:

  1. 對於數據庫索引來說:數據結構B Tree優於AVL Tree的主要原因是減少IO次數提升查詢效率;B+Tree優於B Tree的主要原因是方便了範圍查詢。
  2. B+Tree中所有的數據都存放在葉子節點上,非葉子節點上的數據只用於比較;並且上一個葉子節點的末尾存放了下一個葉子節點起始位置的地址。
  3. MyISAM存儲引擎數據和索引分屬於兩個不同文件;InnoDB中爲同一個文件,並且通過主鍵來組織數據的存儲,是真正的聚合索引。
  4. InnoDB中當通過非主鍵索引查詢數據時,一般情況下是先定位到主鍵,在通過主鍵索引查詢(當查詢字段爲當前非主鍵字段時,就不會也沒必要去查詢主鍵了)

推薦大家一個非常好用的查看不同數據結構存儲過程的鏈接Data Structure Visualizations,可以直觀的看到各種數據結構的存儲過程。

▄█▀█●各位同仁,如果我的代碼對你有幫助,請給我一個贊吧,爲了下次方便找到,也可關注加收藏呀
如果有什麼意見或建議,也可留言區討論

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