MySQL之InnoDB存儲(chǔ)頁(yè)的獨(dú)立表空間解讀
1、背景
我們往一張表里插入的行數(shù)據(jù)是存儲(chǔ)在頁(yè)上的,一張頁(yè)的大小為16KB,數(shù)據(jù)量大的時(shí)候一張頁(yè)不可能存儲(chǔ)完一張表里的所有數(shù)據(jù),所以需要多張頁(yè)來(lái)進(jìn)行存儲(chǔ),這多張頁(yè)所在的存儲(chǔ)空間就叫表空間,表空間分為系統(tǒng)表空間和獨(dú)立表空間,接下來(lái)就講一下獨(dú)立表空間上是如何存儲(chǔ)頁(yè)的。
2、獨(dú)立表空間
【1】表空間大小
之前講過(guò)頁(yè)的組成,我們?cè)賮?lái)看一下頁(yè)的通用部分File Header(38字節(jié)大小)的組成:
| 名稱 | 字節(jié)大小 | 含義 |
|---|---|---|
| FIL_PAGE_SPACE_OR_CHKSUM | 4 | 頁(yè)的校驗(yàn)和 |
| FIL_PAGE_OFFSET | 4 | 頁(yè)號(hào) |
| FIL_PAGE_PREV | 4 | 上一頁(yè) |
| FIL_PAGE_NEXT | 4 | 下一頁(yè) |
| FIL_PAGE_LSN | 8 | 頁(yè)最后被修改時(shí)對(duì)應(yīng)的日志序列位置 |
| FIL_PAGE_TYPE | 2 | 頁(yè)類型 |
| FIL_PAGE_FILE_FLUSH_LSN | 8 | 僅在系統(tǒng)表空間的一個(gè)頁(yè)中定義,代表文件執(zhí)行被刷新到了對(duì)應(yīng)的LSN值 |
| FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | 頁(yè)屬于哪個(gè)表空間 |
File Header里的頁(yè)號(hào)由4字節(jié)組成,也就是32位,所以一個(gè)表空間最多能存儲(chǔ)232個(gè)頁(yè),每個(gè)頁(yè)按照16KB的大小來(lái)算,一個(gè)表空間最多可以存儲(chǔ)64TB的大小的數(shù)據(jù)
【2】區(qū)
表空間里每連續(xù)64個(gè)頁(yè)組成一個(gè)區(qū),一個(gè)頁(yè)按16KB大小來(lái)算,一個(gè)區(qū)的大小就為64*16KB=1MB,如下圖表示:

【3】組
表空間上連續(xù)256個(gè)區(qū)就為一個(gè)組,區(qū)0到區(qū)255就為第一個(gè)組,區(qū)256到區(qū)511就為第二個(gè)組,剩下的以此內(nèi)推,需要注意的是,第一個(gè)組的前三個(gè)頁(yè)的類型是固定,其它組的前兩個(gè)頁(yè)類型是固定的,在講這些頁(yè)之前我們先看一下頁(yè)的類型有幾種:
| 類型 | 含義 |
|---|---|
| FIL_PAGE_UNDO_LOG | Undo日志頁(yè) |
| FIL_PAGE_INODE | 段信息節(jié)點(diǎn) |
| FIL_PAGE_IBUF_FREE_LIST | Insert Buffer空閑列表 |
| FIL_PAGE_IBUF_BITMAP | Insert Buffer位圖 |
| FIL_PAGE_TYPE_SYS | 系統(tǒng)頁(yè) |
| FIL_PAGE_TYPE_TRX_SYS | 事務(wù)系統(tǒng)數(shù)據(jù) |
| FIL_PAGE_TYPE_FSP_HDR | 表空間頭部信息 |
| FIL_PAGE_TYPE_XDES | 擴(kuò)展描述頁(yè) |
| FIL_PAGE_TYPE_BLOB | BLOB頁(yè) |
再看組的表結(jié)構(gòu)圖,如下圖:

【4】段
一個(gè)索引有葉子節(jié)點(diǎn)和非葉子節(jié)點(diǎn),存放葉子節(jié)點(diǎn)所在區(qū)的集合就叫葉子段,存放非葉子節(jié)點(diǎn)所在區(qū)的集合就叫非葉子段,一個(gè)索引有兩個(gè)段。
【5】區(qū)的類型
段就是索引中葉子節(jié)點(diǎn)和非葉子節(jié)點(diǎn)所在區(qū)的集合,一個(gè)索引兩個(gè)段,一個(gè)區(qū)64個(gè)頁(yè),數(shù)據(jù)量小的時(shí)候用一個(gè)區(qū)來(lái)作為存儲(chǔ)單位十分浪費(fèi)空間,所以就有了碎片區(qū)的概念,在數(shù)據(jù)量小的時(shí)候段就以碎片區(qū)中的頁(yè)為單位來(lái)分配空間,數(shù)據(jù)量大的時(shí)候就以區(qū)為單位來(lái)分配存儲(chǔ)空間,碎片區(qū)不屬于任何段,并且碎片區(qū)里的頁(yè)可以存儲(chǔ)多個(gè)索引的數(shù)據(jù),區(qū)的類型有如下幾種:
| 區(qū)類型 | 含義 |
|---|---|
| FREE | 屬于表空間,區(qū)中的頁(yè)都沒被使用 |
| FREE_FRAG | 屬于表空間,有可用頁(yè)的碎片區(qū) |
| FULL_FRAG | 無(wú)可用頁(yè)的碎片區(qū) |
| FSEG | 屬于某個(gè)段的區(qū) |
【6】XDES Entry區(qū)結(jié)構(gòu)
InnoDB中每一個(gè)區(qū)都對(duì)應(yīng)一個(gè)XDES Entry結(jié)構(gòu),其組成圖如下:

XDES Entry結(jié)構(gòu)字段含義如下:
| XDES Entry | 字節(jié)大小 | 含義 |
|---|---|---|
| Segment ID | 8 | 段的唯一編號(hào),只有FSEG類型的區(qū)此字段才有用 |
| List Node | 12 | 指向上一個(gè)和下一個(gè)XDES Entry結(jié)構(gòu) |
| State | 4 | FREE、FREE_FRAG、FULL_FRAG、FSEG四種區(qū)類型 |
| Page State Bitmap | 16 | 16字節(jié)對(duì)應(yīng)的128比特位,其中每2個(gè)比特位對(duì)應(yīng)一個(gè)區(qū)64個(gè)頁(yè)中的一個(gè)頁(yè),2個(gè)比特位中第一個(gè)比特位代表該頁(yè)是否被使用 |
List Node結(jié)構(gòu)字段含義如下:
| List Node | 字節(jié)大小 | 含義 |
|---|---|---|
| Prev Node Page Number | 4 | 上一個(gè)XDES Entry結(jié)構(gòu)所在的頁(yè) |
| Prev Node Offset | 2 | 上一個(gè)XDES Entry結(jié)構(gòu)頁(yè)內(nèi)偏移量 |
| Next Node Page Number | 4 | 下一個(gè)XDES Entry結(jié)構(gòu)所在的頁(yè) |
| Next Node Offset | 2 | 下一個(gè)XDES Entry結(jié)構(gòu)頁(yè)內(nèi)偏移量 |
【7】XDES Entry鏈表
在數(shù)據(jù)量比較小的時(shí)候,段是以碎片區(qū)中的頁(yè)為單位來(lái)分配存儲(chǔ)空間的,插入數(shù)據(jù)方式如下:
- 1、查找表空間中狀態(tài)為FREE_FRAG的區(qū),找到了就取出零碎的頁(yè)把數(shù)據(jù)插進(jìn)去,
- 2、沒找到就申請(qǐng)一個(gè)狀態(tài)為FREE的區(qū),將狀態(tài)變?yōu)镕REE_FRAG,再取出零碎的頁(yè)將數(shù)據(jù)插入進(jìn)去,
- 3、之后再插入數(shù)據(jù)當(dāng)沒有零碎的頁(yè)可用時(shí)狀態(tài)就變?yōu)镕ULL_FRAG。
快速查找這3個(gè)類型的區(qū)通過(guò)3個(gè)鏈表來(lái)查找,這3個(gè)鏈表是屬于表空間獨(dú)有的,3個(gè)鏈表如下:
| 鏈表 | 含義 |
|---|---|
| FREE鏈表 | FREE狀態(tài)的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)通過(guò)List Node組成的鏈表 |
| FREE_FRAG鏈表 | FREE_FRAG狀態(tài)的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)通過(guò)List Node組成的鏈表 |
| FULL_FRAG鏈表 | FULL_FRAG狀態(tài)的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)通過(guò)List Node組成的鏈表 |
當(dāng)一個(gè)段中的數(shù)據(jù)超過(guò)32個(gè)零碎的頁(yè)之后,就以區(qū)為單位來(lái)分配存儲(chǔ)空間了,此時(shí)每個(gè)段都涉及3個(gè)鏈表,注意每個(gè)段都有3個(gè)鏈表,3個(gè)鏈表如下:
| 鏈表 | 含義 |
|---|---|
| FREE鏈表 | 同一個(gè)段中所有頁(yè)都是空閑的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)組成一個(gè)鏈表 |
| NOT_FULL鏈表 | 同一個(gè)段中有空閑頁(yè)的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)組成一個(gè)鏈表 |
| FULL鏈表 | 同一個(gè)段中沒有有空閑頁(yè)的區(qū)對(duì)應(yīng)的XDES Entry結(jié)構(gòu)組成一個(gè)鏈表 |
【8】XDES Entry鏈表基節(jié)點(diǎn)
為了快速找到XDES Entry鏈表的頭和尾,InnoDB中設(shè)計(jì)了鏈表基節(jié)點(diǎn)結(jié)構(gòu)List Base Node,其結(jié)構(gòu)圖如下:

【9】INODE Entry段結(jié)構(gòu)
段也有一個(gè)對(duì)應(yīng)的結(jié)構(gòu)INODE Entry,其結(jié)構(gòu)如圖:

INODE Entry結(jié)構(gòu)字段含義如下:
| INODE Entry | 字節(jié)大小 | 含義 |
|---|---|---|
| Segment Id | 8 | 段的唯一id |
| NOT_FULL_N_USED | 4 | NOT_FULL鏈表中已經(jīng)使用了的頁(yè)數(shù) |
| List Base Node For FREE List | 16 | 對(duì)應(yīng)段中的FREE鏈表 |
| List Base Node For NOT_FULL List | 16 | 對(duì)應(yīng)段中的NOT_FULL鏈表 |
| List Base Node For FULLList | 16 | 對(duì)應(yīng)段中的FULL鏈表 |
| Magic Number | 4 | INODE Entry是否被初始化 |
| Fragment Array Entry | 4 | 零碎頁(yè)頁(yè)號(hào),總共32個(gè) |
【10】FIL_PAGE_TYPE_FSP_HDR頁(yè)類型
表空間第一個(gè)組中第一個(gè)頁(yè)的類型為FIL_PAGE_TYPE_FSP_HDR,結(jié)構(gòu)如下:

FIL_PAGE_TYPE_FSP_HDR字段解釋:
| 字段 | 字節(jié)大小 | 含義 |
|---|---|---|
| File Header | 38 | 頁(yè)的通用信息 |
| FIle Space Header | 112 | 表空間的一些整體屬性 |
| XDES Entry | 10240 | 256個(gè)區(qū)信息 |
| Empty Space | 5986 | 未使用的空間 |
| File Trailer | 8 | 校驗(yàn)頁(yè)是否完整 |
File Space Header結(jié)構(gòu)字段解釋:
| 字段 | 字節(jié)大小 | 含義 |
|---|---|---|
| Space ID | 4 | 表空間ID |
| Not Used | 4 | 未使用 |
| Size | 4 | 表空間占有的頁(yè)數(shù) |
| FREE Limit | 4 | 未被初始化的最小頁(yè)號(hào),大于等于此頁(yè)號(hào)對(duì)應(yīng)的區(qū)的XDES Entry結(jié)構(gòu)都沒被加入FREE鏈表 |
| Space Flags | 4 | 存儲(chǔ)占用空間比較小的屬性 |
| FRAG_N_USED | 4 | FREE_FRAG鏈表中已使用的頁(yè)數(shù)量 |
| List Base Node for FREE List | 16 | FREE鏈表基節(jié)點(diǎn) |
| List Base Node for FREE_FRAG List | 16 | FREE_FRAG鏈表的基節(jié)點(diǎn) |
| List Base Node for FULL_FRAG List | 16 | FULL_FREG鏈表的基節(jié)點(diǎn) |
| Next Unused Segment ID | 8 | 表空間中下一個(gè)未使用的段ID |
| List Base Node for SEG_INODES_FULL List | 16 | SEG_INODES_FULL鏈表的基節(jié)點(diǎn) |
| List Base Node for SEG_INODES_FREE List | 16 | SEG_INODES_FREE鏈表的基節(jié)點(diǎn) |
【11】FIL_PAGE_IBUF_BITMAP頁(yè)類型
表空間所有組的第二個(gè)頁(yè)的類型為FIL_PAGE_IBUF_BITMAP,用于InnoDB存儲(chǔ)引擎中事務(wù)日志緩沖區(qū),與插入緩沖有關(guān),后面再講。
【12】FIL_PAGE_INODE頁(yè)類型
第一組第三個(gè)頁(yè)類型就為FIL_PAGE_INODE,用于存儲(chǔ)段結(jié)構(gòu)INODE Entry,其頁(yè)結(jié)果如圖:

FIL_PAGE_INODE頁(yè)類型字段解釋如下:
| 字段名 | 字節(jié)大小 | 含義 |
|---|---|---|
| File Header | 38 | 頁(yè)的通用信息 |
| List Node for INODE Page List | 12 | 存儲(chǔ)上一個(gè)INODE頁(yè)和下一個(gè)INODE頁(yè) |
| INODE Entry | 16128 | 段信息,可以存儲(chǔ)85個(gè) |
| Empty Space | 6 | 未使用的空間 |
| File Trailer | 8 | 校驗(yàn)頁(yè)是否完整 |
可以看到一個(gè)FIL_PAGE_INODE類型的頁(yè)最多存儲(chǔ)85個(gè)INODE Entry段結(jié)構(gòu),如果超過(guò)85個(gè),就需要申請(qǐng)其它FIL_PAGE_INODE類型的頁(yè)來(lái)進(jìn)行存儲(chǔ)了,所有FIL_PAGE_INODE類型的頁(yè)會(huì)組成兩個(gè)鏈表,這兩個(gè)鏈表存儲(chǔ)在FIL_PAGE_TYPE_FSP_HDR類型頁(yè)的File Space Header結(jié)構(gòu)里,鏈表如下:
| 鏈表 | 含義 |
|---|---|
| SEG_INODES_FULL鏈表 | FIL_PAGE_INODE類型的頁(yè)中沒有空閑空間來(lái)存儲(chǔ)INODE Entry段結(jié)構(gòu) |
| SEG_INODES_FREE鏈表 | FIL_PAGE_INODE類型的頁(yè)中有空閑空間來(lái)存儲(chǔ)INODE Entry段結(jié)構(gòu) |
存儲(chǔ)一個(gè)INODE Entry結(jié)構(gòu)的過(guò)程如下:
- 1、從SEG_INODES_FULL鏈表中取出一個(gè)頁(yè)去存儲(chǔ)INODE Entry段結(jié)構(gòu),
- 2、如果頁(yè)上的INODE Entry段機(jī)構(gòu)存儲(chǔ)滿了就放入SEG_INODES_FREE鏈表,
- 3、如果SEG_INODES_FULL鏈表為空,就從表空間所屬的FREE_FRAG鏈表中取出一個(gè)零碎頁(yè),修改其類型為FIL_PAGE_INODE,再放入SEG_INODES_FULL鏈表中。
【13】FIL_PAGE_TYPE_XDES頁(yè)類型
表空間第一個(gè)組之外的其它組的第一個(gè)頁(yè)類型為FIL_PAGE_TYPE_XDES,和FIL_PAGE_TYPE_FSP_HDR頁(yè)類型差不多,相比少了一些其它屬性,其結(jié)構(gòu)圖如下:

【14】索引關(guān)聯(lián)INODE Entry段結(jié)構(gòu)
一個(gè)索引有兩個(gè)段,它們之間是這樣關(guān)聯(lián)起來(lái)的,數(shù)據(jù)頁(yè)組成的頁(yè)類型中有兩個(gè)字段如下:
| 字段 | 字節(jié)大小 | 含義 |
|---|---|---|
| PAGE_BTR_SEG_LEAF | 10 | B+樹葉子段的頭部信息,只在B+樹的根頁(yè)定義 |
| PAGE_BTR_SEG_TOP | 10 | B+樹非葉子段的頭部信息,只在B+樹的根頁(yè)定義 |
這兩個(gè)字段各對(duì)應(yīng)一個(gè)Segment Header結(jié)構(gòu)如下:
| Segment Header字段 | 字節(jié)大小 | 含義 |
|---|---|---|
| SpaceID ofthe INODE Entry | 4 | INODE Entry結(jié)構(gòu)所在的表空間ID |
| Page Number of the INODE Entry | 4 | INODE Entry結(jié)構(gòu)所在頁(yè)號(hào) |
| Byte Offset of the INODE Ent | 2 | INODE Entry結(jié)構(gòu)在頁(yè)中偏移量 |
通過(guò)Segment Header就能很方便找到索引對(duì)應(yīng)的INODE Entry段結(jié)構(gòu),并且只需要在B+樹的根節(jié)點(diǎn)中定義這兩字段。
3、總結(jié)
本文主要講解獨(dú)立表空間的組成部分,涉及到頁(yè)、區(qū)、組還有各種結(jié)構(gòu)等,后續(xù)可以再講解系統(tǒng)表空間的組成,和獨(dú)立表空間類似。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
避免MySQL中的隱式轉(zhuǎn)換的方法小結(jié)
在 MySQL 中,隱式轉(zhuǎn)換可能導(dǎo)致索引失效、結(jié)果不符合預(yù)期或性能問題,以下是避免隱式轉(zhuǎn)換的具體方法,從表設(shè)計(jì)、查詢編寫到配置優(yōu)化,逐步減少隱式轉(zhuǎn)換的發(fā)生,具體操作過(guò)程跟隨小編一起看看吧2025-04-04
mysql主從數(shù)據(jù)庫(kù)不同步的2種解決方法
今天發(fā)現(xiàn)Mysql的主從數(shù)據(jù)庫(kù)沒有同步,很是疑惑,于是搜索整理了下,接下來(lái)介紹解決方法,有感興趣的朋友可以參考下2013-01-01
mysql 8.0.17 winx64(附加navicat)手動(dòng)配置版安裝教程圖解
這篇文章主要介紹了mysql 8.0.17 winx64(附加navicat)手動(dòng)配置版安裝教程圖解,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08
mysql 從 frm 文件恢復(fù) table 表結(jié)構(gòu)的3種方法【推薦】
這篇文章主要介紹了mysql 從 frm 文件恢復(fù) table 表結(jié)構(gòu)的3種方法 ,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
MySQL查詢隨機(jī)數(shù)據(jù)的4種方法和性能對(duì)比
從MySQL隨機(jī)選取數(shù)據(jù)也是我們最常用的一種發(fā)發(fā),其最簡(jiǎn)單的辦法就是使用”O(jiān)RDER BY RAND()”,本文介紹了包括ORDER BY RAND()的4種獲取隨機(jī)數(shù)據(jù)的方法,并分析了各自的優(yōu)缺點(diǎn)。2014-04-04
linux下導(dǎo)入、導(dǎo)出mysql數(shù)據(jù)庫(kù)命令的實(shí)現(xiàn)方法
下面小編就為大家分享一篇linux下導(dǎo)入、導(dǎo)出mysql數(shù)據(jù)庫(kù)命令的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
MySQL數(shù)據(jù)庫(kù)恢復(fù)(使用mysqlbinlog命令)
binlog是通過(guò)記錄二進(jìn)制文件方式來(lái)備份數(shù)據(jù),然后在從二進(jìn)制文件將數(shù)據(jù)恢復(fù)到某一時(shí)段或某一操作點(diǎn)。2011-08-08
MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法
這篇文章主要介紹了MySQL8.0設(shè)置遠(yuǎn)程訪問權(quán)限的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11

