InnoDB頁面結構

InnoDB所有數據文件(ibdata以及ibd)都由頁組成。頁在內核實現中稱為page或block,page偏向于指向物理頁面,block偏向于指向page被加載到內存后,用來管理page的內存結構。在未被壓縮情況下,一個頁的大小為UNIV_PAGE_SIZE(16384,16K)。不同用途的頁具有相同格式的文件頭和文件尾,其中記錄了頁面校驗值、頁面編號、表空間編號、LSN等通用信息。頁面的組織方式在《InnoDB物理文件結構》中已有介紹,本文將深入InnoDB頁面結構。

1 頁面類型

以MySQL-8.0.30為例,所有頁面類型如下:

類型 含義
FIL_PAGE_INDEX B+樹節點
FIL_PAGE_RTREE R-樹節點,R-tree是專門用來表示空間數據類型
FIL_PAGE_SDI SDI是冗余備份的表元數據信息,同樣以B+樹存儲,此為SDI頁面類型
FIL_PAGE_TYPE_UNUSED 目前此類型暫未使用
FIL_PAGE_UNDO_LOG 存儲undo log的回滾段頁面
FIL_PAGE_INODE 用于管理數據文件中的segment,每個inode頁可以存儲FSP_SEG_INODES_PER_PAGE(默認為85)個記錄
FIL_PAGE_IBUF_FREE_LIST change buffer的空閑鏈表,change buffer介紹詳見《Buffer Pool詳解
FIL_PAGE_TYPE_ALLOCATED 新分配的頁面
FIL_PAGE_IBUF_BITMAP page_no為1、1+16384*N的頁面都是FIL_PAGE_IBUF_BITMAP類型,用于記錄其后16384個頁面change buffer的信息
FIL_PAGE_TYPE_SYS 系統頁
FIL_PAGE_TYPE_FSP_HDR page no 0/16384*N的頁面都是extent描述頁,page no 0還記錄了與該table space相關的信息(FSP HEADER),類型為FIL_PAGE_TYPE_FSP_HDR
FIL_PAGE_TYPE_TRX_SYS 事務系統數據
FIL_PAGE_TYPE_XDES 除page no為0的頁外所有extent描述頁的類型,page no為16384*N
FIL_PAGE_TYPE_BLOB 解壓的BLOB頁面
FIL_PAGE_TYPE_ZBLOB 第一個壓縮的BLOB頁面
FIL_PAGE_TYPE_ZBLOB2 后續壓縮的 BLOB 頁面
FIL_PAGE_TYPE_UNKNOWN 在舊表空間中,FIL_PAGE_TYPE在刷盤時會臨時替換為該值
FIL_PAGE_COMPRESSED 壓縮頁面
FIL_PAGE_ENCRYPTED 加密頁面
FIL_PAGE_COMPRESSED_AND_ENCRYPTED 壓縮和加密頁面
FIL_PAGE_ENCRYPTED_RTREE 加密的 R-tree 頁面
FIL_PAGE_SDI_BLOB 未壓縮的 SDI BLOB 頁面
FIL_PAGE_SDI_ZBLOB 壓縮后的 SDI BLOB 頁面
FIL_PAGE_TYPE_LEGACY_DBLWR 舊的double write buffer頁面
FIL_PAGE_TYPE_RSEG_ARRAY 回滾段數組頁面
FIL_PAGE_TYPE_LOB_INDEX 未壓縮 LOB 的索引頁
FIL_PAGE_TYPE_LOB_DATA 未壓縮 LOB 的數據頁
FIL_PAGE_TYPE_LOB_FIRST 未壓縮 LOB 的第一頁
FIL_PAGE_TYPE_ZLOB_FIRST 壓縮 LOB 的第一頁
FIL_PAGE_TYPE_ZLOB_DATA 壓縮 LOB 的數據頁
FIL_PAGE_TYPE_ZLOB_INDEX 壓縮 LOB 的索引頁。 此頁面包含一個 z_index_entry_t 對象數組。
FIL_PAGE_TYPE_ZLOB_FRAG 壓縮 LOB 的片段頁面
FIL_PAGE_TYPE_ZLOB_FRAG_ENTRY 片段頁的索引頁(壓縮的 LOB)

2 通用頁面結構

任何頁面都有統一的文件頭和文件尾結構,用于記錄頁面的checksum校驗、頁面類型,用于維護邏輯頁面鏈表的前后邏輯頁面編號等。詳細結構如下:

image.png

2.1 Fil Header

名稱 大小 內容
FIL_PAGE_SPACE_OR_CHKSUM 4 MySQL4.0之前為space id,之后為CHECKSUM
FIL_PAGE_OFFSET 4 頁碼,每個表空間從0開始計數。頁碼乘以頁面大小便是當前頁面在數據文件中的偏移
FIL_PAGE_PREV 4 指向B+樹同一層的前一個頁面,第一個頁面的FIL_PAGE_PREV為FIL_NULL
FIL_PAGE_NEXT 4 指向B+樹同一層的下一個頁面,最后一個頁面的FIL_PAGE_NEXT為FIL_NULL
FIL_PAGE_LSN 8 LSN是一個一直遞增的整型數字,表示事務寫入到日志的字節總量,可以唯一區分對數據頁的修改,此處記錄頁面最后一次修改的LSN
FIL_PAGE_TYPE 2 頁面的類型
FIL_PAGE_FILE_FLUSH_LSN 8 兩種作用:1)在系統表空間的第一個頁中,記錄MySQL關閉時checkpoint到的點,即刷入磁盤的頁面LSN至少在該值之上;2)只在FIL_PAGE_COMPRESSED類型的數據頁中被用于記錄壓縮信息
FIL_PAGE_SPACE_ID 4 索引頁所在的表空間的ID

2.2 Fil Trailer

文件尾的作用是校驗文件是否損壞,在每個頁面的結尾的8個字節中,分別存儲了checksum和LSN的后四位,對應于Fil Header中FIL_PAGE_LSN的內容。

3 索引頁結構

InnoDB的用戶表數據存儲于FIL_PAGE_INDEX(通常稱為索引頁)類型的頁面中,是InnoDB最重要的頁面類型之一。下面介紹其頁面結構:

image.png

3.1 Record

為了更好地理解Page Header和Page Directory。先介紹InnoDB索引頁中記錄的排列方式。記錄的格式可以按如下格式理解。

變長字段長度 NULL 標志位 記錄頭信息 系統列 Field 1 ... Field N

其中記錄頭信息中包含了next_record、heap_no、delete_flag、n_owned等重要信息。下面依次介紹:

  • next_record:所有記錄在頁面中從前往后插入。假設id為primary key,id為1,3,2的三條記錄依次插入同一頁面,那么在頁面中三條記錄的排列順序也為1,3,2。三條記錄通過next_record屬性相連,即id為1的記錄的next_record指向id為2的記錄,id為2的記錄next_record指向id為3的記錄。
  • heap_no:記錄在頁面中的物理編號,上述id為1,3,2的三條記錄的heap_no依次為N,N+1,N+2。
  • delete_flag:記錄被刪除后并不是直接在頁面中抹去,而是標記上delete_flag。這樣做的目的是為了多版本并發控制服務(MVCC)。頁面中被delete mark的記錄也會通過next_record串聯成鏈表,記錄在Page Header中。當記錄不再被MVCC需要時,會由purge線程從頁面中徹底抹去。
  • n_owned:本屬性與Page Directory相關,在Page Directory小節中介紹。

每個索引頁為了方便對頁內記錄的訪問,都添加了兩條系統記錄,它們沒有變長字段列表和NULL值列表,只包含記錄頭信息和真實數據:infimum和supremum,分別代表虛擬的最小記錄和虛擬最大記錄。這兩條記錄固定在Page Header之后,分別是heap_no為0和heap_no為1的記錄。從虛擬記錄infimum開始一直通過next_record指針訪問到虛擬記錄supremum,可以按邏輯大小遍歷頁內的所有記錄。

3.2 Page Directory

InnoDB B+樹記錄查詢只能查詢到數據頁級別。假設一條記錄的大小50字節,一個16384字節的頁面可以存儲300條記錄左右,如果頁內查詢如果都通過next_record從infimum遍歷到supremum,那么查詢將非常低效。

Page Directory如其名,作為數據目錄,是用來加速頁內記錄查找的。其由一個個slot組成,每個slot由兩個字節組成,每個Slot指向一條記錄,Slot的值是記錄在頁面內的偏移。每個Slot管理4~8條記錄。被指向的記錄作為組長記錄,管理位于其之前的4-8條記錄。組長記錄的n_owned為其管理的記錄數量。

image.png

如圖所示,Rec5管理Rec1-Rec5,n_owned為5;Rec10管理Rec6-Rec10,n_owned為5;Rec11管理Rec11-Rec14,n_owned為4;Rec18管理Rec15-Rec18,n_owned為4。

一個page至少有兩個Slot,第一個slot指向infimum記錄,最后一個Slot指向supremum記錄。Slot分配是從頁面的最后倒數8個字節的Fil Trailer開始逆序分配的,所以嚴格意義上上圖的Slot1-Slot4應該逆序。

在查找時首先數據目錄上對Slot進行二分查找,定位到具體的slot后,然后在Slot內進行順序查找。

3.3 Free Space

這部分是介于用戶記錄和Page Directory之間的一塊連續的未被使用的內存。用戶記錄從前往后增長,Page Directory從后往前增長。在空間足夠時,會直接從這里分配內存,當空間不足時,會重新整理頁面內的記錄,將碎片空間進行合并,或者分裂頁面,具體行為取決于InnoDB各場景下的具體策略。在將空間分配給記錄后,會遞增PAGE_N_RECS和PAGE_N_HEAP的值。

3.4 Page Header

有了前三小節的介紹,下面對Page Header進行介紹。Page Header主要索引頁內的統計信息,包含14部分,如下所示:

名稱 大小 含義
PAGE_N_DIR_SLOTS 2 Page directory中的Slot個數
PAGE_HEAP_TOP 2 空余空間的起始地址在頁內的偏移,如有新數據將從此位置插入
PAGE_N_HEAP 2 頁面內所有的記錄數:系統記錄(Infimum和Supremum記錄)、用戶記錄、標記被刪除的記錄。標記刪除記錄并不會減少此值。
PAGE_FREE 2 指向被標記刪除的記錄鏈表的第一個記錄。通過此記錄可以訪問所有標記刪除的記錄
PAGE_GARBAGE 2 被標記刪除的所有記錄占用的總字節數,即可回收的空間大小
PAGE_LAST_INSERT 2 指向最近一次被插入記錄的偏移量
PAGE_DIRECTION 2 最近一次記錄插入的方向(從左或從右插入),每次插入時與PAGE_LAST_INSERT的記錄進行比較,以確認插入方向
PAGE_N_DIRECTION 2 當前以相同方向順序插入記錄的個數
PAGE_N_RECS 2 頁面上有效的用戶記錄的個數(不包括最小和最大記錄以及被標記為刪除的記錄)
PAGE_MAX_TRX_ID 8 修改當前頁面的最大事務ID,主要用于輔助判斷二級索引記錄的可見性。
PAGE_LEVEL 2 當前頁面在B+樹中所在的層數,葉子結點的值為0
PAGE_INDEX_ID 8 索引ID,表示當前頁屬于哪個索引
PAGE_BTR_SEG_LEAF 10 僅僅在B+樹root頁定義,葉子節點段在inode page中的位置
PAGE_BTR_SEG_TOP 10 僅僅在B+樹root頁定義,非葉子節點段在inode page中的位置

4 總結

本文在《InnoDB物理文件結構》的基礎上進一步介紹了InnoDB的頁面結構。首先介紹了所有InnoDB的頁面類型,接著介紹了InnoDB頁面的通用頁面結構Fil Header和Fil Trailer,最后從Record、Page Directory、Free Space和Page Header四個方面介紹了InnoDB索引頁的結構。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容

  • 一、頁 1、數據庫的存儲結構——頁 索引結構給我們提供了高效的索引方式,不過索引信息以及數據記錄都是保存在文件上的...
    紫荊秋雪_文閱讀 266評論 0 0
  • 不同類型的頁簡介 前邊我們簡單提了一下頁的概念,它是InnoDB管理存儲空間的基本單位,一個頁的大小一般是16KB...
    tracy_668閱讀 1,164評論 1 6
  • 簡介 從InnoDB邏輯存儲結構來看,InnoDB所有數據都存放到在一個空間中,稱之為表空間。如圖所示,表空間由段...
    呼呼菜菜閱讀 507評論 0 2
  • 自己分析一下ibd文件還是蠻有意思的,能夠學到不少東西,建議跟著走一遍,慢慢領會作者設計的意圖人學東西總是先感性的...
    漫步無法人生閱讀 3,895評論 2 11
  • 1. 索引組織表 ? 在InnoDB存儲引擎中,表都是根據主鍵順序組織存放的,這種存儲方式的表稱為索引...
    Benjamin_Lee閱讀 162評論 0 0