MySQL之InnoDB存儲頁的獨立表空間解讀
1、背景
我們往一張表里插入的行數(shù)據(jù)是存儲在頁上的,一張頁的大小為16KB,數(shù)據(jù)量大的時候一張頁不可能存儲完一張表里的所有數(shù)據(jù),所以需要多張頁來進行存儲,這多張頁所在的存儲空間就叫表空間,表空間分為系統(tǒng)表空間和獨立表空間,接下來就講一下獨立表空間上是如何存儲頁的。
2、獨立表空間
【1】表空間大小
之前講過頁的組成,我們再來看一下頁的通用部分File Header(38字節(jié)大小)的組成:
名稱 | 字節(jié)大小 | 含義 |
---|---|---|
FIL_PAGE_SPACE_OR_CHKSUM | 4 | 頁的校驗和 |
FIL_PAGE_OFFSET | 4 | 頁號 |
FIL_PAGE_PREV | 4 | 上一頁 |
FIL_PAGE_NEXT | 4 | 下一頁 |
FIL_PAGE_LSN | 8 | 頁最后被修改時對應的日志序列位置 |
FIL_PAGE_TYPE | 2 | 頁類型 |
FIL_PAGE_FILE_FLUSH_LSN | 8 | 僅在系統(tǒng)表空間的一個頁中定義,代表文件執(zhí)行被刷新到了對應的LSN值 |
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4 | 頁屬于哪個表空間 |
File Header里的頁號由4字節(jié)組成,也就是32位,所以一個表空間最多能存儲232個頁,每個頁按照16KB的大小來算,一個表空間最多可以存儲64TB的大小的數(shù)據(jù)
【2】區(qū)
表空間里每連續(xù)64個頁組成一個區(qū),一個頁按16KB大小來算,一個區(qū)的大小就為64*16KB=1MB,如下圖表示:
【3】組
表空間上連續(xù)256個區(qū)就為一個組,區(qū)0到區(qū)255就為第一個組,區(qū)256到區(qū)511就為第二個組,剩下的以此內推,需要注意的是,第一個組的前三個頁的類型是固定,其它組的前兩個頁類型是固定的,在講這些頁之前我們先看一下頁的類型有幾種:
類型 | 含義 |
---|---|
FIL_PAGE_UNDO_LOG | Undo日志頁 |
FIL_PAGE_INODE | 段信息節(jié)點 |
FIL_PAGE_IBUF_FREE_LIST | Insert Buffer空閑列表 |
FIL_PAGE_IBUF_BITMAP | Insert Buffer位圖 |
FIL_PAGE_TYPE_SYS | 系統(tǒng)頁 |
FIL_PAGE_TYPE_TRX_SYS | 事務系統(tǒng)數(shù)據(jù) |
FIL_PAGE_TYPE_FSP_HDR | 表空間頭部信息 |
FIL_PAGE_TYPE_XDES | 擴展描述頁 |
FIL_PAGE_TYPE_BLOB | BLOB頁 |
再看組的表結構圖,如下圖:
【4】段
一個索引有葉子節(jié)點和非葉子節(jié)點,存放葉子節(jié)點所在區(qū)的集合就叫葉子段,存放非葉子節(jié)點所在區(qū)的集合就叫非葉子段,一個索引有兩個段。
【5】區(qū)的類型
段就是索引中葉子節(jié)點和非葉子節(jié)點所在區(qū)的集合,一個索引兩個段,一個區(qū)64個頁,數(shù)據(jù)量小的時候用一個區(qū)來作為存儲單位十分浪費空間,所以就有了碎片區(qū)的概念,在數(shù)據(jù)量小的時候段就以碎片區(qū)中的頁為單位來分配空間,數(shù)據(jù)量大的時候就以區(qū)為單位來分配存儲空間,碎片區(qū)不屬于任何段,并且碎片區(qū)里的頁可以存儲多個索引的數(shù)據(jù),區(qū)的類型有如下幾種:
區(qū)類型 | 含義 |
---|---|
FREE | 屬于表空間,區(qū)中的頁都沒被使用 |
FREE_FRAG | 屬于表空間,有可用頁的碎片區(qū) |
FULL_FRAG | 無可用頁的碎片區(qū) |
FSEG | 屬于某個段的區(qū) |
【6】XDES Entry區(qū)結構
InnoDB中每一個區(qū)都對應一個XDES Entry結構,其組成圖如下:
XDES Entry結構字段含義如下:
XDES Entry | 字節(jié)大小 | 含義 |
---|---|---|
Segment ID | 8 | 段的唯一編號,只有FSEG類型的區(qū)此字段才有用 |
List Node | 12 | 指向上一個和下一個XDES Entry結構 |
State | 4 | FREE、FREE_FRAG、FULL_FRAG、FSEG四種區(qū)類型 |
Page State Bitmap | 16 | 16字節(jié)對應的128比特位,其中每2個比特位對應一個區(qū)64個頁中的一個頁,2個比特位中第一個比特位代表該頁是否被使用 |
List Node結構字段含義如下:
List Node | 字節(jié)大小 | 含義 |
---|---|---|
Prev Node Page Number | 4 | 上一個XDES Entry結構所在的頁 |
Prev Node Offset | 2 | 上一個XDES Entry結構頁內偏移量 |
Next Node Page Number | 4 | 下一個XDES Entry結構所在的頁 |
Next Node Offset | 2 | 下一個XDES Entry結構頁內偏移量 |
【7】XDES Entry鏈表
在數(shù)據(jù)量比較小的時候,段是以碎片區(qū)中的頁為單位來分配存儲空間的,插入數(shù)據(jù)方式如下:
- 1、查找表空間中狀態(tài)為FREE_FRAG的區(qū),找到了就取出零碎的頁把數(shù)據(jù)插進去,
- 2、沒找到就申請一個狀態(tài)為FREE的區(qū),將狀態(tài)變?yōu)镕REE_FRAG,再取出零碎的頁將數(shù)據(jù)插入進去,
- 3、之后再插入數(shù)據(jù)當沒有零碎的頁可用時狀態(tài)就變?yōu)镕ULL_FRAG。
快速查找這3個類型的區(qū)通過3個鏈表來查找,這3個鏈表是屬于表空間獨有的,3個鏈表如下:
鏈表 | 含義 |
---|---|
FREE鏈表 | FREE狀態(tài)的區(qū)對應的XDES Entry結構通過List Node組成的鏈表 |
FREE_FRAG鏈表 | FREE_FRAG狀態(tài)的區(qū)對應的XDES Entry結構通過List Node組成的鏈表 |
FULL_FRAG鏈表 | FULL_FRAG狀態(tài)的區(qū)對應的XDES Entry結構通過List Node組成的鏈表 |
當一個段中的數(shù)據(jù)超過32個零碎的頁之后,就以區(qū)為單位來分配存儲空間了,此時每個段都涉及3個鏈表,注意每個段都有3個鏈表,3個鏈表如下:
鏈表 | 含義 |
---|---|
FREE鏈表 | 同一個段中所有頁都是空閑的區(qū)對應的XDES Entry結構組成一個鏈表 |
NOT_FULL鏈表 | 同一個段中有空閑頁的區(qū)對應的XDES Entry結構組成一個鏈表 |
FULL鏈表 | 同一個段中沒有有空閑頁的區(qū)對應的XDES Entry結構組成一個鏈表 |
【8】XDES Entry鏈表基節(jié)點
為了快速找到XDES Entry鏈表的頭和尾,InnoDB中設計了鏈表基節(jié)點結構List Base Node,其結構圖如下:
【9】INODE Entry段結構
段也有一個對應的結構INODE Entry,其結構如圖:
INODE Entry結構字段含義如下:
INODE Entry | 字節(jié)大小 | 含義 |
---|---|---|
Segment Id | 8 | 段的唯一id |
NOT_FULL_N_USED | 4 | NOT_FULL鏈表中已經使用了的頁數(shù) |
List Base Node For FREE List | 16 | 對應段中的FREE鏈表 |
List Base Node For NOT_FULL List | 16 | 對應段中的NOT_FULL鏈表 |
List Base Node For FULLList | 16 | 對應段中的FULL鏈表 |
Magic Number | 4 | INODE Entry是否被初始化 |
Fragment Array Entry | 4 | 零碎頁頁號,總共32個 |
【10】FIL_PAGE_TYPE_FSP_HDR頁類型
表空間第一個組中第一個頁的類型為FIL_PAGE_TYPE_FSP_HDR,結構如下:
FIL_PAGE_TYPE_FSP_HDR字段解釋:
字段 | 字節(jié)大小 | 含義 |
---|---|---|
File Header | 38 | 頁的通用信息 |
FIle Space Header | 112 | 表空間的一些整體屬性 |
XDES Entry | 10240 | 256個區(qū)信息 |
Empty Space | 5986 | 未使用的空間 |
File Trailer | 8 | 校驗頁是否完整 |
File Space Header結構字段解釋:
字段 | 字節(jié)大小 | 含義 |
---|---|---|
Space ID | 4 | 表空間ID |
Not Used | 4 | 未使用 |
Size | 4 | 表空間占有的頁數(shù) |
FREE Limit | 4 | 未被初始化的最小頁號,大于等于此頁號對應的區(qū)的XDES Entry結構都沒被加入FREE鏈表 |
Space Flags | 4 | 存儲占用空間比較小的屬性 |
FRAG_N_USED | 4 | FREE_FRAG鏈表中已使用的頁數(shù)量 |
List Base Node for FREE List | 16 | FREE鏈表基節(jié)點 |
List Base Node for FREE_FRAG List | 16 | FREE_FRAG鏈表的基節(jié)點 |
List Base Node for FULL_FRAG List | 16 | FULL_FREG鏈表的基節(jié)點 |
Next Unused Segment ID | 8 | 表空間中下一個未使用的段ID |
List Base Node for SEG_INODES_FULL List | 16 | SEG_INODES_FULL鏈表的基節(jié)點 |
List Base Node for SEG_INODES_FREE List | 16 | SEG_INODES_FREE鏈表的基節(jié)點 |
【11】FIL_PAGE_IBUF_BITMAP頁類型
表空間所有組的第二個頁的類型為FIL_PAGE_IBUF_BITMAP,用于InnoDB存儲引擎中事務日志緩沖區(qū),與插入緩沖有關,后面再講。
【12】FIL_PAGE_INODE頁類型
第一組第三個頁類型就為FIL_PAGE_INODE,用于存儲段結構INODE Entry,其頁結果如圖:
FIL_PAGE_INODE頁類型字段解釋如下:
字段名 | 字節(jié)大小 | 含義 |
---|---|---|
File Header | 38 | 頁的通用信息 |
List Node for INODE Page List | 12 | 存儲上一個INODE頁和下一個INODE頁 |
INODE Entry | 16128 | 段信息,可以存儲85個 |
Empty Space | 6 | 未使用的空間 |
File Trailer | 8 | 校驗頁是否完整 |
可以看到一個FIL_PAGE_INODE類型的頁最多存儲85個INODE Entry段結構,如果超過85個,就需要申請其它FIL_PAGE_INODE類型的頁來進行存儲了,所有FIL_PAGE_INODE類型的頁會組成兩個鏈表,這兩個鏈表存儲在FIL_PAGE_TYPE_FSP_HDR類型頁的File Space Header結構里,鏈表如下:
鏈表 | 含義 |
---|---|
SEG_INODES_FULL鏈表 | FIL_PAGE_INODE類型的頁中沒有空閑空間來存儲INODE Entry段結構 |
SEG_INODES_FREE鏈表 | FIL_PAGE_INODE類型的頁中有空閑空間來存儲INODE Entry段結構 |
存儲一個INODE Entry結構的過程如下:
- 1、從SEG_INODES_FULL鏈表中取出一個頁去存儲INODE Entry段結構,
- 2、如果頁上的INODE Entry段機構存儲滿了就放入SEG_INODES_FREE鏈表,
- 3、如果SEG_INODES_FULL鏈表為空,就從表空間所屬的FREE_FRAG鏈表中取出一個零碎頁,修改其類型為FIL_PAGE_INODE,再放入SEG_INODES_FULL鏈表中。
【13】FIL_PAGE_TYPE_XDES頁類型
表空間第一個組之外的其它組的第一個頁類型為FIL_PAGE_TYPE_XDES,和FIL_PAGE_TYPE_FSP_HDR頁類型差不多,相比少了一些其它屬性,其結構圖如下:
【14】索引關聯(lián)INODE Entry段結構
一個索引有兩個段,它們之間是這樣關聯(lián)起來的,數(shù)據(jù)頁組成的頁類型中有兩個字段如下:
字段 | 字節(jié)大小 | 含義 |
---|---|---|
PAGE_BTR_SEG_LEAF | 10 | B+樹葉子段的頭部信息,只在B+樹的根頁定義 |
PAGE_BTR_SEG_TOP | 10 | B+樹非葉子段的頭部信息,只在B+樹的根頁定義 |
這兩個字段各對應一個Segment Header結構如下:
Segment Header字段 | 字節(jié)大小 | 含義 |
---|---|---|
SpaceID ofthe INODE Entry | 4 | INODE Entry結構所在的表空間ID |
Page Number of the INODE Entry | 4 | INODE Entry結構所在頁號 |
Byte Offset of the INODE Ent | 2 | INODE Entry結構在頁中偏移量 |
通過Segment Header就能很方便找到索引對應的INODE Entry段結構,并且只需要在B+樹的根節(jié)點中定義這兩字段。
3、總結
本文主要講解獨立表空間的組成部分,涉及到頁、區(qū)、組還有各種結構等,后續(xù)可以再講解系統(tǒng)表空間的組成,和獨立表空間類似。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
mysql 8.0.17 winx64(附加navicat)手動配置版安裝教程圖解
這篇文章主要介紹了mysql 8.0.17 winx64(附加navicat)手動配置版安裝教程圖解,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08mysql 從 frm 文件恢復 table 表結構的3種方法【推薦】
這篇文章主要介紹了mysql 從 frm 文件恢復 table 表結構的3種方法 ,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-09-09MySQL查詢隨機數(shù)據(jù)的4種方法和性能對比
從MySQL隨機選取數(shù)據(jù)也是我們最常用的一種發(fā)發(fā),其最簡單的辦法就是使用”O(jiān)RDER BY RAND()”,本文介紹了包括ORDER BY RAND()的4種獲取隨機數(shù)據(jù)的方法,并分析了各自的優(yōu)缺點。2014-04-04linux下導入、導出mysql數(shù)據(jù)庫命令的實現(xiàn)方法
下面小編就為大家分享一篇linux下導入、導出mysql數(shù)據(jù)庫命令的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12MySQL數(shù)據(jù)庫恢復(使用mysqlbinlog命令)
binlog是通過記錄二進制文件方式來備份數(shù)據(jù),然后在從二進制文件將數(shù)據(jù)恢復到某一時段或某一操作點。2011-08-08