mysql学习之详解InnoDB的表空间
来源:SegmentFault
时间:2023-02-16 19:56:21 381浏览 收藏
对于一个数据库开发者来说,牢固扎实的基础是十分重要的,golang学习网就来带大家一点点的掌握基础知识点。今天本篇文章带大家了解《mysql学习之详解InnoDB的表空间》,主要介绍了MySQL、面试、数据库、InnoDB,希望对大家的知识积累有所帮助,快点收藏起来吧,否则需要时就找不到了!
表空间
表空间(tablespace)由段(sagment)组成,段由区(extent)组成,区由页(page)组成,页由行组成。如下图所示。
所有数据都存放在表空间中。如果用户手动启用了参数innodb_file_per_table,则每张表的数据可以单独放在一个表空间中。
段
逻辑上的概念,⼀个索引会⽣成2个段,⼀个叶⼦节点段(存放叶⼦节点的区),⼀个⾮叶⼦节点段(存放⾮叶⼦节点的区)。
在刚开始向表中插⼊数据的时候,段是从某个碎⽚区(并不是所有页都是存储一个段的数据的区)以⻚为单位来分配存储空间的。
当某个段已经占⽤了32个碎⽚区⻚⾯之后,就会以完整的区为单位来分配存储空间(原先占用的碎片区的页不会被复制到新的区中来)。
常见的段由数据段,索引段,回滚段等。
区结构
对于16KB的页,物理位置连续的64个页就是一个区(extend),大小1MB。256个区被划分为1个组。
每个组中第一个区的固定页如下图所示。
第一组中第0区开始的3个⻚的类型是固定的:
FSP_HDR(16KB):整个表空间的⼀些整体属性以及本组所有的区,整个表空间只有⼀个该类型的⻚⾯。
IBUF_BITMAP(16KB):本组所有的区的所有⻚⾯关于INSERT BUFFER的信息。
INODE(16KB):存储了许多 INODE 的数据结构。
其余各组最开始的 2 个⻚⾯的类型是固定的:
XDES ( extent descriptor):本组 256 个区的属性。
IBUF_BITMAP:存储本组所有的区的所有⻚⾯关于 INSERT BUFFER 的信息。
在表中数据量⼤的时候,为某个索引分配空间的时候就不再按照⻚为单位分配了,⽽是按照区为单位分配。
区分类
空闲的区:FREE,还没有⽤到这个区中的任何⻚⾯。
有剩余空间的碎⽚区:FREE_FRAG,表示碎⽚区中还有可⽤的⻚⾯。
没有剩余空间的碎⽚区:FULL_FRAG,表示碎⽚区中的所有⻚⾯都被使⽤,没有空闲⻚⾯。
附属于某个段的区:FSEG。
区的XDES Entry
结构
为了方便管理区而设计的。共40个字节,分为4个部分。
SegmentID(8字节):段唯一编号,表示就是该区所在的段(前提是该区已被分配给某段了,否则该字段无意义)。
ListNode(12字节):PreNodePageNumber(4字节,前一页的页号)和PreNodeOffset(2字节,前一页的页号在页内的偏移量)指向前⼀个XDESEntry。NextNodePageNumber(4字节,后一页的页号)和NextNodeOffset(2字节,后一页的页号在页内的偏移量)指向后⼀个XDESEntry。
State:区的状态。参见“InnoDB表空间-区分类”条目。
PageStateBitmap:128个⽐特位。每2个⽐特位对应区中的⼀个⻚。第⼀个位表示对应的⻚是否是空闲的(1空闲。0不空闲),第⼆个⽐特位还没有⽤(1没用。0用了)。
XDES Entry链表
通过List Node把FREE区对应的XDES Entry链接成一个链表,叫FREE链表。同一段中所有页面是空闲的区的XDES Entry会被加到这个链表。
通过List Node把FREE_FRAG区对应的XDES Entry链接成一个链表,叫FREE_FRAG链表。同一段中还有空闲页面区的XDES Entry会被加到这个链表。
通过List Node把FULL_FRAG区对应的XDES Entry链接成一个链表,叫FREE_FRAG链表。同一段中没有空闲页面区的XDES Entry会被加到这个链表。
每个XDES Entry链表会有一个List Base Node节点,会被放在段的INODE Entry。其中。
ListLength:该链表总节点数。
FirstNodePageNumber和FirstNodeOffset:该链表的头节点在表空间中的位置。
LastNodePageNumber和LastNodeOffset:该链表的尾节点在表空间中的位置。
段的INODE Entry
为了方便管理段而设计的。共192字节,被分为如下几个部分。
Segment ID(8字节):该INODE Entry对应的段号。
NOT_FULL_N_USED(4字节):NOT_FULL链表的各XDES Entry节点对应的区已经使⽤了多少⻚⾯。⼀个区中有64个⻚⾯,如果不标记已经使⽤了多少⻚⾯的话,每次向段中插⼊数据的时候都要从第⼀个⻚⾯进⾏遍历寻找空闲⻚⾯,有了这个字段之后就可以快速定位空闲⻚⾯。
3个List Base Node(分别都为16字节):分别为段的FREE链表、NOT_FULL链表、FULL链表定义了ListBaseNode。
Magic Number:标记这个INODE Entry是否已经被初始化了(值是97937874,表明已经初始化,否则没有被初始化)。
Fragment Array Entry:段是由零散的页面和完整的区组成。每个Fragment Array Entry结构都对应着⼀个零散的⻚⾯,这个结构⼀共4个字节,表示⼀个零散⻚⾯的⻚号。
页类型
FSP_HDR类型
表空间的第一个页面,也是第一个组的第一个页面,页号为0,存储表空间的整体属性及第一个组内内256区对应的XDES Entry结构。如下表所示。
名称 | 描述 | 占用空间(字节) | 作用 |
---|---|---|---|
File Header | ⽂件头部 | 38 | 页的通用信息 |
File Space Header | 表空间头部 | 112 | 表空间的⼀些整体属性信息 |
XDES Entry | 区描述信息 | 10240 | 存储本组256个区对应的属性信息 |
Empty Space | 尚未使⽤ 空间 | 5986 | ⻚结构的填充 |
File Trailer | ⽂件尾部 | 8 | 校验⻚是否完整 |
File Space Header如下表所示。
名称 | 占用空间(字节) | 描述 |
---|---|---|
Space ID | 4 | 表空间的ID |
Not Used | 4 | 未使⽤ |
Size | 4 | 当前表空间占有的⻚⾯数 |
FREE Limit | 4 | 尚未被初始化的最⼩⻚号,⼤于或等于这个⻚号的区对应的XDES Entry结构都没有被加⼊FREE链表 |
Space Flags | 4 | 表空间的⼀些占⽤存储空间⽐较⼩的属性,不同MySQL版本有些差异 |
FRAG_N_USED | 4 | FREE_FRAG链表中已使⽤的⻚⾯数量 |
3个List Base Node | 16/16/16 | FREE/FREE_FREG/FULL_FREG链表的基节点 |
Next Unused Segment ID | 8 | 当前表空间中下⼀个未使⽤的Segment ID |
List Base Node for SEG_INODES_FULL List | 16 | SEG_INODES_FULL链表的基节点 |
List Base Node for SEG_INODES_FREE List | 16 | SEG_INODES_FREE链表的基节点 |
XDES类型
除了第一个分组的第一个页面是FSP_HDR类型之外,之后的每个分组的第⼀个⻚⾯只需要记录本组内所有的区对应的XDES Entry结构即可。就叫它XDES类型。如下图所示。
IBUF_BITMAP类型
每个分组的第⼆个⻚⾯的类型都是这种类型,这种类型的⻚⾥边记录了⼀些有关Change Buffer的信息。本质是一颗B+树。
在修改非唯一二级索引页面时,如果页面尚未被加载到内存中,那么该修改会被暂时存储到Change Buffer中,等服务器空闲或者对应页面从磁盘加载到内存时,再将修改合并到对应的页面。
INDOE类型
第⼀个分组的第三个⻚⾯。记录段的相关信息,如下表所示。
名称 | 描述 | 占用空间(字节) | 作用 |
---|---|---|---|
File Header | ⽂件头部 | 38 | 页的通用信息 |
List Node for INODE Page List | 通用链表节点 | 12 | 存储上下两个INODE页面的指针。如果一个表空间超过85个INODE Entry,则需要额外的该类型页面来存储。 |
INODE Entry | 段描述信息 | 16320 | 具体的INODE Entry结构 |
Empty Space | 尚未使⽤空间 | 6 | ⻚结构的填充 |
File Trailer | ⽂件尾部 | 8 | 校验⻚是否完整 |
INDOE类型页面被划分为两个链表:
SEG_INODES_FULL链表:该链表中的INODE类型的⻚⾯中已经没有空闲空间来存储额外的INODE Entry结构了。
SEG_INODES_FREE链表:该链表中的INODE类型的⻚⾯中还有空闲空间来存储额外的INODE Entry结构了。
新建段时,会创建INODE Entry,存储INODE Entry的过程如下:
先看SEG_INODES_FREE链表是否为空,若不为空,直接从该链表中获取节点(页面),并把新的INDODE Entry放进去。当节点(页面)无空余空间时,就把该节点(页面)放到SEG_INODES_FREE中去。
若SEG_INODES_FREE为空,则需要从表空间的FREE_FRAG链表中申请一个页面,并将该页面的类型修改为INODE,并加入SEG_INODES_FREE链表,然后把INODE Entry结构放入该页面。
Segement Header结构
数据页的Page Header中有这两个字段:PAGE_BTR_SEG_LEA(10字节,B+树叶⼦节点段的头部信息,仅在B+树的根⻚定义),PAGE_BTR_SEG_TOP(10字节,B+树⾮叶⼦段的头部信息,仅在B+树的根⻚定义)。
这俩字段对应一个Segment Header组成,如下图所示。
名称 | 占用空间(字节) | 描述 |
---|---|---|
Space ID of the INODE Entry | 4 | INODE Entry结构所在的表空间ID |
Page Number of the INODE Entry | 4 | INODE Entry结构所在的⻚⾯⻚号 |
Byte Offset of the INODE Entry | 2 |
系统表空间
独立表空间用于记录用户数据(上述内容都是讲的独立表空间),系统表空间用于记录一些与整个系统有关的信息。
系统表空间表空间ID(SpaceID)是0。
第一个区的前三个页面与独立表空间是一致的,但第4个页面到第8个页面(页号从3到7)是系统表空间独有的,如下表所示。
页号 | 页面类型 | 英文名称 | 作用 |
---|---|---|---|
3 | SYS | Insert Buffer Header | 存储Insert Buffer的头部信息 |
4 | INDEX | Insert Buffer Root | 存储Insert Buffer的根⻚⾯ |
5 | TRX_SYS | Transction System | 事务系统的相关信息 |
6 | SYS | First Rollback Segment | 第⼀个回滚段的⻚⾯ |
7 | SYS | Data Dictionary Header | 数据字典头部信息,下文会讲到 |
后续区的前两个页面与独立表空间对应的区的页面是一致的。
元数据
更好地管理用户数据而引入的额外数据称为元数据。
记录元数据的系统表如下表所示。用户不能直接访问InnoDB的系统表。
表名 | 作用 |
---|---|
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存储引擎中所有的虚拟⽣成列的信息 |
如下四个表尤为重要,且这四个表的元数据硬编码到代码中了。
SYS_TABLES表
(NAME为主键,ID列为二级索引)
表名 | 作用 |
---|---|
NAME | 表名 |
ID | InnoDB存储引擎中每个表都有⼀个唯⼀的ID |
N_COLS | 该表拥有列的个数 |
TYPE | 表的类型,记录了⼀些⽂件格式、⾏格式、压缩等信息 |
MIX_ID | 忽略 |
MIX_LEN | 忽略 |
CLUSTER_ID | 忽略 |
SPACE | 该表所属表空间的ID |
SYS_COLUMNS表
(以TABLE_ID,POS为主键)
表名 | 作用 |
---|---|
TABLE_ID | 该列所属表对应的ID |
POS | 该列在表中是第⼏列 |
NAME | 列的名称 |
MTYPE | 表的类型,记录了⼀些⽂件格式、⾏格式、压缩等信息 |
PRTYPE | 主数据类型,例如INT、VARCHAR |
LEN | 该列最多占⽤存储空间的字节数 |
PREC | 忽略 |
SYS_INDEXES表
(TABLE_ID,ID为主键)
表名 | 作用 |
---|---|
TABLE_ID | 该索引所属表对应的ID |
ID | InnoDB存储引擎中每个索引都有⼀个唯⼀的ID |
N_FIELDS | 该索引包含列的个数 |
TYPE | 索引的类型,⽐如聚簇索引、唯⼀索引 |
SPACE | 该索引根页面所在的表空间ID |
PAGE_NO | 该索引根页面所在页号 |
MERGE_THRESHOLD | 如果⻚⾯中的记录被删除MERGE_THRESHOLD,就把该⻚⾯和相邻⻚⾯合并 |
SYS_FIELDS表
(INDEX_ID,ID为主键)
表名 | 作用 |
---|---|
INDEX_ID | 该列所属索引的ID |
POS | 该列在索引中是第几列 |
COL_NAME | 列名 |
Data Dictionary Header页面:用固定的⻚⾯来记录上述4个表的聚簇索引和⼆级索引对应的B+树位置,这个⻚⾯就是⻚号为7的⻚⾯。如下图与表所示。
名称 | 描述 | 占用空间(字节) | 作用 |
---|---|---|---|
File Header | ⽂件头部 | 38 | 页的通用信息 |
Data Dictionary Header | 数据字典头部 | 52 | 记录⼀些基本系统表的根⻚⾯位置以及InnoDB存储引擎的⼀些全局信息 |
Unused | 未使用 | 4 | 未使用 |
Segment Header | 段头部 | 10 | 记录本⻚⾯所在段对应的INODEEntry位置信息 |
Empty Space | 尚未使⽤空间 | 6 | ⻚结构的填充 |
File Trailer | ⽂件尾部 | 8 | 校验⻚是否完整 |
Data Dictionary Header详解
MaxRowID:不论哪个拥有row_id列(InnoDB隐藏列)的表插⼊⼀条记录时,该记录的row_id列的值就是MaxRowID对应的值,然后再把MaxRowID对应的值加1,也就是说这个MaxRowID是全局共享的。
MaxTableID:InnoDB存储引擎中的所有的表都对应⼀个唯⼀的ID,每次新建⼀个表时,就会把本字段的值作为该表的ID,然后⾃增本字段的值。
MaxIndexID:InnoDB存储引擎中的所有的索引都对应⼀个唯⼀的ID,每次新建⼀个索引时,就会把本字段的值作为该索引的ID,然后⾃增本字段的值。
MaxSpaceID:InnoDB存储引擎中的所有的表空间都对应⼀个唯⼀的ID,每次新建⼀个表空间时,就会把本字段的值作为该表空间的ID,然后⾃增本字段的值。
MixIDLow(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表聚簇索引的根⻚⾯的⻚号。
结尾
InnoDB的表空间就讲完了,希望大家能持续学习。下一篇MySQL文章讲InnoDB-数据目录。
微信扫描下方二维码,或搜索“xicheng”,关注公众号后回复【笔记】,有我准备的15万字Java面试笔记。
感谢各位人才的点赞、收藏和评论,干货文章持续更新中,下篇文章再见!
理论要掌握,实操不能落!以上关于《mysql学习之详解InnoDB的表空间》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
-
499 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
101 收藏
-
208 收藏
-
174 收藏
-
317 收藏
-
371 收藏
-
244 收藏
-
288 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 机灵的花生
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢up主分享文章内容!
- 2023-03-09 12:15:39
-
- 含糊的日记本
- 这篇博文太及时了,up主加油!
- 2023-03-04 15:56:45
-
- 火星上的凉面
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享文章内容!
- 2023-02-27 16:34:06
-
- 直率的美女
- 这篇文章内容太及时了,太详细了,赞 👍👍,码住,关注作者大大了!希望作者大大能多写数据库相关的文章。
- 2023-02-26 13:04:50
-
- 积极的水蜜桃
- 这篇技术贴真及时,好细啊,太给力了,mark,关注老哥了!希望老哥能多写数据库相关的文章。
- 2023-02-25 23:24:49
-
- 洁净的可乐
- 太细致了,mark,感谢大佬的这篇文章,我会继续支持!
- 2023-02-22 05:09:37
-
- 发嗲的大炮
- 这篇博文出现的刚刚好,太详细了,真优秀,码起来,关注作者了!希望作者能多写数据库相关的文章。
- 2023-02-18 13:50:49