mysql innodb索引結構及相關原理

最近在優化線上代碼,優化過程中,對數據庫進行了一系列的學習和基礎鞏固,看了很多大佬寫的文章,整理了一下,記錄在這裏~

參考文檔:

B+tree的結構

在操作系統中,當我們往磁盤中取數據的時候,如果我們想要取出1kb的數據時,會發現,操作系統取出了4kb的數據,這是因爲操作系統中的大小是4kb。這是爲什麼呢?

當一個程序訪問了一條數據之後,很有可能在此訪問這條數據或訪問這條數據相鄰的數據。因此,乾脆直接把4kb的數據全部取出,放到內存中,下次再來訪問時,直接從內存中取出,減少了磁盤IO。

假設,我們現在有一張用戶表,我們要找出id=5的數據,在沒了解頁這個概念之前,最原始的方法就是遍歷。我們會不斷的從磁盤中取出一條數據,然後判斷這條數據是不是id=5,如果不等於,會繼續向後遍歷,此時,我們會查找5次,也就是經過了5次磁盤IO。

現在,我們將頁引入,當我們取出id=1的數據時,操作系統會將id=1所在頁的全部數據(id=1到id=4)取出,放到內存中,我們繼續向後遍歷,接下來的遍歷,會從內存中取出;當取出id=5的數據時,操作系統會再次將該id所在頁全部取出。此時我們會發現,只經過了2次磁盤IO

在MySQL的InnoDb引擎中,頁的大小是16KB,是操作系統的4倍,而int類型的數據是4個字節,其它類型的數據的字節數通常也在4000字節以內,所以一頁是可以存放很多很多條數據的,而MySQL的數據正是以爲基本單位組合而成的。

頁的結構如下:
在這裏插入圖片描述

頁目錄

通過對上面頁的瞭解,我們在查找數據的時候,已經可以做到減少磁盤IO了。但是我們可以發現其實頁中的數據結構就是一個鏈表鏈表的優點是插入和刪除很快,但是查詢需要按指針方向去遍歷。假設現在一頁中有上百萬條數據,最壞的情況他可能會遍歷上百萬次,即使在內存中,效率也不高。

頁目錄就像書目錄一樣,會告訴我們哪個標題從哪一頁開始。頁目錄的結構如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lag5GLOy-1577436044948)(evernotecid://FBE381A3-17C7-41D9-AA37-9C5F29FAB396/appyinxiangcom/20545635/ENResource/p158)]

假設我們查找id=3的數據,首先會找到目錄2,然後對目錄2中的數據進行查找。當然我們能通過目錄快速的找到數據,其實主要基於這些數據已經經過了排序。因此,可以得知,在我們插入數據時,數據庫會對數據進行排序。

當然,不可能只有一頁數據,多頁數據的結構如下:在這裏插入圖片描述
但是需要注意的是,在開闢新頁的時候,數據並不一定在新開闢的頁上,而是需要進行和所有頁的數據的比較,從而來決定數據存放的位置

目錄頁

從上圖我們可以發現,多頁之間也是通過指針相連,他們其實就是鏈表。如果頁的數量過多,又會造成遍歷過多,此時,我可以想到,有沒有一個結構,可以像頁目錄那樣,可以優化頁內數據呢?

頁內數據和多頁他們本質上都是鏈表,所以我們可以採用相同的方式優化,這種方式叫目錄頁。
在這裏插入圖片描述
需要注意的是,目錄頁的本質也是頁,但是,普通頁中村的數據是項目數據,而目錄頁中村的數據是普通頁的地址。

B+tree

在這裏插入圖片描述
從上面的圖我們已經可以看出,這其實就是b+tree的結構了。一般來說,樹的深度是3層;每個葉子就是數據頁,非葉子結點就是目錄頁;葉子結點存放真實的數據,而非葉子結點存放目錄,也就是索引。

它的優勢有以下幾點:

  1. 由於葉子結點上存放了所有的數據,並且有指針相連,每個葉子結點在邏輯上是相連的,所以對範圍查找比較友好;
  2. B+tree所有的數據都在葉子結點上,所以查詢效率穩定,一般都是查詢三次;
  3. 有利於數據庫的掃描;
  4. 有利於磁盤的IO,因爲他的層高不會因爲數據擴大而增高(三層樹高大概可以存放2000萬的數據量);

InnoDB索引

我們都知道innodb索引的結構是B+tree,那麼,他是怎樣存放數據的呢?
在這裏插入圖片描述
通過上面的圖,我們可以得到以下信息:innodb的數據文件本身就是按B+tree組織的索引結構,葉子結點存放了表的完整數據,key是數據表的主鍵,因此,innodb數據表文件本身就是主索引

像這種葉子結點包含完整數據的結構,我們叫它聚簇索引。聚簇索引是按照每張表的主鍵構造的一顆B+樹,樹的葉子結點存放着表中行數據。由於每張表的主鍵只有一個,因此數據庫中每張表只有一個聚簇索引。
因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。

除了主索引,還有輔助索引。每張表的輔助索引可以有多個,它的葉子結點不同於主索引,輔助索引存儲着相應記錄主鍵的值。也就是說,innodb的所有輔助索引都引用主鍵作爲data。
在這裏插入圖片描述

輔助索引也可以叫做非聚簇索引。非聚簇索引就是將數據和索引分開,查找時需要先查找到索引,然後通過索引回表找到相應的數據。

因爲所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大,所以不建議使用過長的字段作爲主鍵。

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