MySQL核心解析 Innodb頁面儲存結構 1

2022-07-15 05:27:09 字數 3515 閱讀 6524

本文介紹innodb的索引資料頁面儲存結構,主要介紹資料頁面的整體結構,而頁面的詳細結構將會在另一篇中介紹。

1. b+樹

閱讀本文前,首先要知道一些關於b樹的基礎知識。innodb的乙個表可能包含多個索引,每個索引都使用b+樹來儲存。而索引包括聚集索引和二級索引,聚集索引使用表的主鍵作為索引鍵,包含表的所有字段。二級索引只包含索引鍵和聚集索引鍵(主鍵)的內容,不包括其他字段。每乙個索引都是一棵b+樹,每棵b+樹由很多頁面組成,而每個頁面大小一般為16k。從b+樹的組織結構來看,b樹的頁面可分為:

乙個b+樹的結構大概為

圖1 b+樹的總體結構

從上圖可知,相同層次的頁面是用乙個雙向鍊錶連線起來的。一般情況下,從b+樹的最左邊葉子節點開始,一直向右掃瞄,就可以得到b+樹的從小到大的所有資料。因此,對於葉子節點,有如下特徵:

那麼,下文主要介紹兩方面內容:

2. 頁面儲存格式

乙個頁面的儲存格式如下圖顯示:

圖2 innodb頁面儲存格式

從上圖得,乙個頁面的儲存由以下幾部分組成:

1.頁頭(page header

2.最小虛記錄、最大虛記錄:兩個固定位置儲存的虛記錄,本身並不儲存資料。最小虛記錄比任何記錄都小,而最大虛記錄比任何記錄都大。

3.記錄堆(record heap:指上圖的橙黃色部分。表示頁面已分配的記錄空間,也是索引資料的真正儲存區域。記錄堆分為兩種,即有效記錄已刪除記錄。有效記錄就是索引正常使用的記錄,而已刪除記錄表示索引已經刪除,不在使用的記錄,如上圖的深藍色部分。隨著記錄的更新和刪除越來越頻繁,記錄堆中已刪除記錄將會越多,即會出現越來越多的空洞(碎片)。這些已刪除記錄連線起來,就會成為頁面的自由空間鍊錶

4.未分配空間:指頁面未使用的儲存空間,隨著頁面不斷使用,未分配空間將會越來越小。當新插入一條記錄時,首先嘗試從自由空間鍊錶中獲得合適的儲存位置(空間足夠),如果沒有滿足的,就會在未分配空間中申請。

5.slot:slot是一些頁面有效記錄的指標,每個slot佔兩個位元組,儲存了記錄相對頁面首位址的偏移。如果頁面有n條有效記錄,那麼slot的數量就在n/8+2~n/4+2之間。下一節詳細介紹slot區,它是記錄頁面有序和二分查詢的關鍵。

6.頁尾(page tailer:頁面最後部分,佔8個位元組,主要儲存頁面的校驗資訊。

頁面中的頁頭,最大/最小虛記錄以及頁尾都是頁面中有固定的儲存位置。而我們最關心的頁面結構可能是記錄堆以及slot區。那麼,頁面記錄如何保證有序的呢?看下節的介紹。

3. 如何保證有序

上文說到,資料頁內的資料是按索引鍵有序的。那麼怎麼保證這種有序性呢?我們先分析一些可能做法。

普通做法1

在記錄堆中,記錄是按儲存順序排序的,即rec1

普通做法2

換一種做法,如果頁面記錄不是按儲存空間有序,而是使用乙個鍊錶連線起來,從鏈頭到鏈尾依次有序。那麼插入一條記錄,只要修改前後兩記錄的指標就行,這樣就可以避免記錄的移動同時保證了有序性。但是,帶來的問題是,鍊錶是無法使用二分查詢的,這樣的設計會導致查詢效率低下。

文藝做法:

為了減少頁面記錄的移動,保證頁面資料的有序性,同時滿足二分查詢的要求,可以在頁面的尾部空間中分配了slot區。每乙個slot佔兩個位元組,儲存記錄相對頁面的偏移。並且slot對應的記錄是從右往左(從高位址到低位址)依次有序的,例如圖2中s2對應的記錄必定大於s1指向的記錄。

現假設乙個slot對應一條記錄,如slot1對應rec_a,slot2對應rec_b,slot3對應rec_c,以此類推,並且rec_a

如果查詢記錄,由於每乙個slot的大小固定並且空間是連續的,就可以通過二分查詢來定位記錄。

個人認為這是比較文藝的做法,但我們看看innodb比較2b的真正做法。

innodb真正的2b做法:

圖3 頁面記錄邏輯組織結構

事實上,innodb頁面記錄都已經通過乙個鍊錶維護起來,並且從鏈頭到鏈尾依次增大(普通方法2)。這種方式之前也已經說到,是無法使用二分查詢。為了解決這個問題,innodb使用若干slot指向鏈的某些記錄,而不是slot跟記錄一一對應,如圖3所示。

slot指向的記錄依然保證著從右往左依次有序的特性,我們使用rec[s2]表示s2指向的記錄,那麼rec[s2]>rec[s1]。另外,本文稱兩個slot之間的記錄稱為乙個slot支鏈,如圖3虛線圈住的部分,表示s2指向的slot支鏈。innodb維護的slot支鏈高度為4-8,如果乙個支鏈的高度超過或不足,會導致相應的支鏈拆分和合併操作。

如何查詢?

如果在頁面中查詢記錄r1(為簡單起見,假設索引鍵是唯一的)。首先通過二分查詢定位slot號x,滿足

rec[x-1]< r1 <= rec[x]

那麼記錄r1要麼不存在,要麼就在slot支鏈x中。接著就是遍歷這條支鏈,找到真正記錄。但支鏈的搜尋只能一一遍歷,不能使用二分查詢。

如何插入?

首先通過查詢的方式確定插入的slot支鏈和插入位置,在自由空間鍊錶或未分配空間中獲得空間並寫記錄內容,slot支鏈高度加1,同時維護好原鍊錶的關係。

插入記錄後,如果slot支鏈高度超過8,那麼就將該支鏈拆分為兩個子鏈,同時多申請乙個slot(平移此slot及其後面的空間)。

這樣設計有什麼好處?

這種設計相當於文藝做法有什麼好處呢?想了很久,只想到了乙個,就是減少了slot的分配和移動。然而,這樣設計的缺點倒是不少。

從訪問效率上,不能完全的二分查詢,需要使用二分查詢+順序遍歷,查詢效能也有所折扣。

從複雜度上,大大增大**的複雜度。

是不是某些巧妙的地方需要這樣的設計來達到更好的效能呢?也有這種可能,但暫時還沒發現。而我所知的有些資料庫更多是用那種「文藝」的設計方案。

參考《mysql技術內幕-innodb儲存引擎》

MySQL核心 InnoDB儲存引擎 試讀

mysql核心 innodb儲存引擎 卷1 從原始碼層次分析了innodb的體系結構 原理 工作機制等,結合實踐案例,對我們想深入學習mysql innodb 核心原理來說,是不可多得的好書。思考 mysql innodb引擎同 myisam 的比較 myisam是非事務安全型,而innodb是事務...

十九 InnoDB核心引數

default storage engine innodb 儲存引擎設定引數 innodb file per table 1 預設獨立表空間模式 innodb data file path ibdata1 512m ibdata2 512m autoextend 共享表空間檔案個數跟大小配置 inn...

mysql日誌 InnoDB 監控

參考官方文件 innodb監視器提供有關innodb內部狀態的資訊。此資訊對效能調整很有用。14.17.1 innodb 監控型別 innodb監視器有兩種型別 innodb鎖定監視器列印額外的鎖定資訊作為標準innodb監視器輸出的一部分。14.17.2 啟用 innodb 監控 當innodb監...