MySQL表空间
2023-03-16 09:17:40 2 举报
MySQL表空间,可能是最全的表空间逻辑构成图,带你遨游MySQL表空间的秘密
作者其他创作
大纲/内容
在系统表空间中会额外记录一些有关整个系统信息的页面,所以会比独立表空间多出一些记录这些信息的页面.它的表空间 ID (Space ID)是 0
Space ID
4 字节
表空间ID
Not Used
未被使用
Size
当前表空间占有的页面数
FREE Limit
尚未被初始化的最小页号
Space Flags
表空间的一些占用存储空间比较小的属性
FRAG_N_USED
FREE_FRAG链表中已使用的页面数量
List Base Node for FREE List
16 字节
FREE链表的基节点
List Base Node for FREE_FRAGList
FREE_FREG链表的基节点
List Base Node for FULL_FRAGList
FULL_FREG链表的基节点
Next Unused Segment ID
8 字节
当前表空间中下一个未使用的 Segment ID
List Base Node forSEG_INODES_FULL List
SEG_INODES_FULL链表的基节点
List Base Node forSEG_INODES_FREE List
SEG_INODES_FREE链表的基节点
有空间
FSP_HDR:1. 记录整个表空间的一些属性2. 记录本组所有的区的一些属性(extent0-extent255)3. 整个表空间只有一个 FSP_HDR 类型的页面
表名
描述
SYS_TABLES
整个InnoDB存储引擎中所有的表的信息
SYS_COLUMNS
整个InnoDB存储引擎中所有的列的信息
SYS_INDEXES
整个InnoDB存储引擎中所有的索引的信息
SYS_FIELDS
整个InnoDB存储引擎中所有的索引对应的列的信息
SYS_FOREIGN
整个InnoDB存储引擎中所有的外键的信息
SYS_FOREIGN_COLS
整个InnoDB存储引擎中所有的外键对应列的信息
SYS_TABLESPACES
整个InnoDB存储引擎中所有的表空间信息
SYS_DATAFILES
整个InnoDB存储引擎中所有的表空间对应文件系统的文件路径信息
SYS_VIRTUAL
整个InnoDB存储引擎中所有的虚拟生成列的信息
如何知道表空间的哪些区是Free_FRAG、Free、Full_FRAG的呢?可以 遍历XDES Entry的状态,但效率太低所有表空间维护了3个链表:FREE 链表FREE_FRAG 链表FULL_FRAG 链表这样我们想找一个 FREE_FRAG 状态的区时,就直接把 FREE_FRAG 链表的头节点拿出来,然后插入数据。后续操作这三个链表就可以了问题来了,如何找到这3个链表呢:链表基点存储在span style=\
数据字典(元数据)
extent 0中的页
系统表空间的 extent 1 和 extent 2 这两个区,也就是页号从 64 ~ 191这128个页面被称为 Doublewrite buffer ,也就是双写缓冲区
方便之后在空闲碎片链表中查找空闲的页面
每256个区(extent)为一组
XDES Entry
直属于表空间的链表基点FREE 链表:状态为 FREE 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表FREE_FRAG 链表:状态为 FREE_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表FULL_FRAG 链表:状态为 FULL_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表
属于段的
INODE Entry
show databases ;-- information_schema系统数据库-- 用户是不能直接访问InnoDB的内部系统表的,除非你直接去解析系统表空间对应文件系统上的文件-- 查看这些表的内容可能有助于大家分析问题,所以在系统数据库information_schema中提供了一些以 innodb_sys 开头的表.USE information_schema;SHOW TABLES LIKE 'innodb_sys%';
申请完整的区来插入数据
总结:1. 表空间被划分为连续的多个区2. 每256个区为一组3. 每组的前几个页面时固定的
前二个页是固定的
List Base Node
16Byte*8=128bit128个比特位被划分为64个部分,每个部分2个比特位,对应区中的一个页一个区64个页两个比特位的第一个位表示对应的页是否是空闲的,第二个比特位还没有用到
前三个页是固定的
段由32个零散页和区组成
从该区中取一些零碎的页把数据插进去
Free_FRAG
未满
为什么需要元数据
List Length
该链表一共有多少节点
First Node Page Number
First Node Offset
2 字节
Last Node Page Number
Last Node Offset
插入数据的本质是向表中叶子节点段和非叶子节点段插入数据
Max Row ID
row_id主键
Max Table ID
表对应一个唯一的ID
Max Index ID
索引对应一个唯一的ID
Max Space ID
表空间对应一个唯一的ID
Mix ID Low
Unused
Root of SYS_TABLES clust index
SYS_TABLES 表聚簇索引的根页面的页号
Root of SYS_TABLE_IDS sec index
SYS_TABLES 表为 ID 列建立的二级索引的根页面的页号
Root of SYS_COLUMNS clust index
SYS_COLUMNS 表聚簇索引的根页面的页号
Root of SYS_INDEXES clust index
SYS_INDEXES 表聚簇索引的根页面的页号
Root of SYS_FIELDS clust index
SYS_FIELDS 表聚簇索引的根页面的页号
为什么引入区?页太多了,如果范围查询的话,涉及到随机I/O。按区分配空间的话,那一个区也就是64个页都是物理连续的。
定位系统表(数据字典)
插入数据
extent 512中的页
File Space Header
操作表空间的3个链表
指向XDES ENTY链表尾节点
表空间
独立表空间
一个表空间中可能存在超过85个段,一个 INODE 类型的页面不足以存储所有的段对应的 INODE Entry 结构,所以就需要额外的 INODE 类型的页面来存储这些结构。为了方便管理这些 INODE 类型的页面,将这些 INODE 类型的页面串联成两个不同的链表:SEG_INODES_FULL 链表 和 SEG_INODES_FREE 链表
指向XDES ENTY链表头节点
根据这个状态连接成不同的链表
1. 一个表,只有一个主键索引的时候,那么就有2个段,每个段维护3个链表,总共6个链表2. 表空间需要维护3个链表所以,总共需要维护9个链表,插入数据时就是这9个链表互相的移动
FSP_HDR(16KB)
0区中的第1个页
IBUF_BITMAP(16KB)
0区中的第2个页
INODE(16KB)
0区中的第3个页
Insert Buffer Header
0区中的第4个页页面类型:SYS
Insert Buffer Root
0区中的第5个页页面类型:INDEX
Transction System
0区中的第6个页页面类型:TRX_SYS
First Rollback Segment
0区中的第7个页页面类型:SYS
Data Dictionary Header
0区中的第8个页页面类型:SYS
...
End
INODE (16KB)
INODE 类型的页会组成两种列表:FULL 链表:该链表中的 INODE 类型的页面都已经被 INODE Entry 结构填充满FREE 链表:该链表中的 INODE 类型的页面都已经仍有空闲空间来存放 INODE Entry 结构
INODE Entry结构中32个零散页段=区+零散页
没空间
状态值
说明
FREE
空闲的区
FREE_FRAG
有剩余空间的碎片区
FULL_FRAG
没有剩余空间的碎片区
FSEG
附属于某个段的区
基本系统表
File Header
38 字节
页的一些通用信息
List Node for INODE Page List
12 字节
上一个INODE页面和下一个INODE页面的指针
INODE Entry 0
192字节
INODE Entry结构
INODE Entry 1
INODE Entry 84
Empty Space
6 字节
尚未使用空间
File Trailer
校验页是否完整
为了延迟初始化
查找某个段的某个链表的头节点和尾节点的时候,就可以直接到这个部分找到对应链表的 List Base Node每一个链表对应有一个 List Base Node
记录一些基本系统表的根页面位置以及InnoDB存储引擎的一些全局信息
申请一个状态为FREE的区,修改状态为Free_FRAG
32个零散页面
FSP_HDR (16KB)
已满
1. 表空间时一个抽象的概念2. 对于系统表空间来说,对应着文件系统一个或多个实际文件3. 对于独立表空间来说,对应着文件系统中一个名为”表名.ibd“的实际文件
extent 256中的页
属于表空间的
1. 一个区有连续的64个页组成(16KB*64=1024)2. 每256个区被划分成一组
文件头部页的一些通用信息
Data DictionaryHeader
52字节
数据字典头部信息
Segment Header
10字节
段头部信息
16272字节
用于页结构的填充,没使用
文件尾部校验页是否完整
Segment ID
8字节
该区所在的段
List Node
12字节
XDES Entry链表
State
4字节
区的状态
Page State Bitmap
16字节
页状态
如果区还没分配给某个段,这个值就没意义
记录本页面所在段对应的INODE Entry位置信息
Free_FRAG状态修改为Full_FRAG
操作属于段的3个链表
段中32个页
如何查看元数据
每当我们向一个表中插入一条记录的时候,MySQL先要校验一下插入语句对应的表存不存在,插入的列和表中的列是否符合,如果语法没有问题的话,还需要知道该表的聚簇索引和所有二级索引对应的根页面是哪个表空间的哪个页面,然后把记录插入对应索引的 B+ 树中。这就用到了这些元数据
extent 0 (1M)
extent 1 (1M)
extent 2 (1M)
extent ... (1M)
extent 255 (1M)
extent 256 (1M)
extent 257 (1M)
extent 258 (1M)
extent 511(1M)
extent 512(1M)
extent 513(1M)
extent 514(1M)
extent ...(1M)
extent 768(1M)
112 字节
表空间的一些整体属性信息
XDES Entry 0
40 字节
对应本组第0个区属性信息
XDES Entry 1
对应本组第1个区属性信息
XDES Entry 255
对应本组第255个区属性信息
5986 字节
可以把表空间想象成被切分为许多个 页 的池子,当我们要在某个表插入一条记录的时候,就从池子中找到对应页,然后把数据写进去
表中每个索引都对应2个段,每个段都有一个唯一的ID,那当我们为某个表新创建一个索引的时候,就意味着要创建两个新的段。该字段表明当前表空间中最大的段ID的下一个ID,这样在创建新段的时候赋予新段一个唯一的ID值就非常方便了
是否插满Free_FRAG
INODE Entry 结构对应的段的编号(ID)
NOT_FULL_N_USED
NOT_FULL 链表中已经使用了多少个页面
List Base Node For Free List
16 字节
FREE 链表
List Base Node For Full List
FULL 链表
List Base Node For NOT_Full_List
NOT_FULL 链表
Magic Number
标记是否初始化
Fragment Array Entry 0
对应零散的页面(页号)
Fragment Array Entry 1
Fragment Array Entry 2
Fragment Array Entry ...
Fragment Array Entry 31
表空间都对应着具体的磁盘文件,一开始我们创建表空间的时候对应的磁盘文件中都没有数据,所以我们需要对表空间完成一个初始化操作,包括为表空间中的区建立 XDES Entry 结构,为各个段建INODE Entry 结构、建立各种链表等。我们可以一开始就为表空间申请一个特别大的空间,但是实际上有绝大部分的区是空闲的,我们可以选择把所有的这些空闲区对应的 XDES Entry 结构加入FREE 链表,也可以选择只把一部分的空闲区加入 FREE 链表,等啥时候空闲链表中的 XDES Entry 结构对应的区不够使了,再把之前没有加入 FREE 链表的空闲区对应的 XDES Entry 结构加入 FREE 链表,中心思想就是啥时候用到啥时候初始化, FREE Limit 这个字段,在该字段表示的页号之前的区都被初始化了,之后的区尚未被初始化
段的3个链表对应的基节点
每当我们创建一个索引时,就会创建2个段,也就是会创建2个 INODE Entry 结构流程如下:1.SEG_INODES_FREE 链表不为空,则拿出来INODE,存储一个INODE Entry 结构,存满就移动到SEG_INODES_FULL 链表2.SEG_INODES_FREE 链表为空,从表空间的FREE_FRAG 链表中申请一个页面,修改该页面的类型为 INODE ,把该页面放到 SEG_INODES_FREE 链表中,与此同时,存储一个INODE Entry 结构
0区中的第一个页
0区中的第二个页
0区中的第三个页
0区中的第N个页
0区中的第64个页
申请完整的区来插入数据,我们怎么哪些区属于哪个段?可以遍历XDES Entry结构中状态为FSEG状态的区,但效率太低根据SegmentId把FSEG状态的区组成链表,这样有1个问题,就是这个链表中有的区已经满了,有的区还可以插入数据,所有需要在细分一下,最后形成属于段的3个链表:FREE 链表:同一个段中,所有页面都是空闲的区对应的 XDES Entry 结构NOT_FULL 链表:同一个段中,还有空闲空间的区对应的 XDES Entry 结构FULL 链表:同一个段中,已经没有空闲空间的区对应的 XDES Entry 结构问题来了,如何找到这3个链表呢:链表基点存储在List Base Node中
XDES(16KB)
链表的基点存储在这里
数字是值的 97937874 ,表明该 INODE Entry 已经初始化,否则没有被初始化
Pre Node Page Number
指向前一个 XDES Entry 的指针
Pre Node Offset
Next Node Page Number
指向后一个 XDES Entry 的指针
Next Node Offset
系统表空间
0 条评论
下一页