201_mysql_innodb_2_表空间_独立表空间_段_区

举报
alexsully 发表于 2021/10/26 15:20:01 2021/10/26
【摘要】 表空间_独立表空间_段_区

select @@innodb_file_per_table;  #1

独立表空间迁移

#1. 锁定源端t1表
flush tables test.t1 with read lock;
 show create table test.t1;

#2. 目标端创建test库和t100w空表
#3. 单独删除空的表空间文件
alter table test.t1 discard tablespace;
# 4. 拷贝源端ibd文件到目标端目录,并设置权限
cp /data/3306/data/test/t1.ibd /data/3307/data/test/
chown -R mysql.mysql /data/*
#5. 导入表空间
mysql> alter table test.t1import tablespace;

# 备注:mysqlutils & 8.0自带命令ibd2sdi 看表结构
mysqlfrm –diagnostic  /usr/local/mysql/data/test/new_table.frm  #5.7 
ibd2sdi city.ibd  #8.0

 

InnoDB 表空间 = 被切分为多个页的池子

独立表空间

区(extent) 为了方便管理表空间内多个页,抛出的概念,

  • 一个区extent(1M) = 64page(16KB)
  • 256个去被分成一组, extent0 ~extent255 是第一组, extent256 ~extent512第二组
  • Extent0最开始的三个页面是固定的页面类型:FSP_HDR, IBUF_BITMAP,  INODE

FSP_HDR类型:用来登记整个表空间的一些整体属性以及本组所有的区,也就是 extent 0 ~ extent 255区的属性 整个表空间只有一个 FSP_HDR 类型的页面

IBUF_BITMAP类型:这个类型的页面是存储本组所有区的所有页面关于 INSERT BUFFER的信息

INODE类型:这个类型的页面存储了许多称为 INODE 的数据结构

其余各组最开始的2个页面的类型是固定的

 XDES类型 extent descriptor,用来登记本组256个区的属性,也就是说对于在 extent 256区中的该类型页面存储的就是extent 256 ~ extent 511 这些区的属性

(FSP_HDR类型的页面其实和 XDES 类型的页面的作用类似,只不过FSP_HDR类型的页面还会额外存储一些表空间的属性)

IBUF_BITMAP类型:存储本组所有区的所有页面关于 INSERT BUFFER的信息

二 段的概念 segment

链表中相邻的两个物理页位置离得非常远,会产生随机 I/O, 尽量让链表中相邻的页的物理位置也相邻(顺序IO)引出的 extent的概念,一次分配64个页,可以连续分配多个页, 消除随机IO

  • 扫描范围其实对B+树叶子节点扫描,如果不分叶子/非叶子节点,都放在区中的话,效果会很差
  • InnoDB B+树的叶子节点喝非叶子节点进行区别对待,也就是说叶子节点/非叶子节点都有自己独有的区
  • 存放叶子节点的区的集合算是一个段(segment),存放非叶子节点的区的集合也算是一个段
  • 也就是说一个索引会生成两个段,一个叶子节点段,一个非叶子节点段

2.1 申请段过程

  1.  一般情况下 一张表只有一个聚簇索引(两个段, 叶子/非叶子段
  2. 初始化时候 大家都使用 fragment(碎片区) 这些区属于不同的 segment
  3. 最开始 从fragment中以单个页面为单位 分配存储空间, 当某个段已经占了32个碎片区的页面, 就会以完整的区来分配
  4. :某些零散的页 以及一些完整的区的集合(叶子节点段/非叶子节点段,回滚段等)


区的4大分类/状态

状态名

归属

含义

FREE

直属表空间

空闲的区, 现在还没用到这个区中的任何页面

FREE_FRAG

直属表空间

有剩余空间的碎片区,表示碎片区中还有可用的页面

FULL_PAGE

直属表空间

没有剩余空间的碎片区,表示碎片区中的所有页面都被使用,没有空闲页面

FSEG

属于某个段

附属于某个段的区, 每一个索引都可以分为叶子节点段和非叶子节点段

InnoDB 还会另外定义一些特殊作用的段,在这些段中的数据量很大时将被使用区作为基本的分配单位


2.2 XDES Entry的结构

InnoDB设计XDES Entry的结构(Extent Descriptor Entry)每一个区都对应着一个XDES Entry 结构,这个结构记录了对应的区的一些属性。这个结构的示意图如下

2.2.1 Segment ID (8字节)

每一个段都有一个唯一的编号,ID表示,此处的 Segment ID字段表示就是该区所在的段。

2.2.2 List Node (12字节)

 可以将若干个 XDES Entry 结构串联成一个链表

如果我们想定位表空间内的某一个位置的话,只需指定页号以及该位置在指定页号中的页内偏移量即可。所以:

Pre Node Page Number Pre Node Offset 的组合就是指向前一个 XDES Entry 的指针。

Next Node Page Number Next Node Offset 的组合就是指向后一个 XDES Entry 的指针。

 

2.2.3 Page State Bitmap (16字节 128个比特位)

一个区默认有64个页,这128个比特位被划分为64个部分,每个部分2个比特位,对应区中的一个页

Page State Bitmap部分的第1和第2个比特位对应着区中的第1个页面,第3/4个比特位对应着区中的第2个页面,

这两个比特位的第一个位表示对应的页是否是空闲的,第二个比特位还没有用

2.2.4 STATE 对应四大状态


2.3 XDES Entry 链表 初衷是减少随机IO且节约空间(数据量小少的浪费空间)

常规流程:

1 查看是否有FREE_FRAG区,如没有申请一个状态为Free的区, 同时更改该去状态 FREE_FRAG,

2 不同段往这个区写数据直到写满(FULL_FRAG

抛出问题:如何知道区是FREE FREE_FRAG, FULL_FRAG

利用 XDES Entry 中的 List Node的指针做链表

把状态为 FREE 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表称为 FREE 链表(直属表空间)

把状态为 FREE_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表称为 FREE_FRAG 链表 (直属表空间)

把状态为 FULL_FRAG 的区对应的 XDES Entry 结构通过 List Node 来连接成一个链表,这个链表称为 FULL_FRAG 链表(直属表空间)


InnoDB为每个段中的区对应的XDES Entry 结构建立了三个链表 (来确认哪些区属于哪个段)

FREE 链表:同一个段中,所有页面都是空闲的区对应的 XDES Entry 结构会被加入到这个链表。注意和直属于表空间的 FREE 链表区别开了,此处的 FREE 链表是附属于某个段的

NOT_NULL 链表:同一个段中,仍有空闲空间的区对应的 XDES Entry 结构会被加入到这个链表中

FULL 链表:同一个段中,已经没有空闲空间的区对应的 XDES Entry 结构会被加入到这个链表


综上 每一个索引都对应两个段,每个段都会维护上述的3个链表

create table tt (
    c1 int not null auto_increment,
    c2 varchar(100),
    c3 varchar(100),
    primary key (c1),
    key idx_c2(c2)
)ENGINE=InnoDB;

这个表共有两个索引,一个聚簇索引,一个二级索引,
所以这个表共有4个段,每个段都会维护上述3个链表,总共12个链表,
加上直属于表空间的3个链表,
整个独立表空间需要维护15个链表

所以段在数据量比较大时插入数据的话,会先获取 NOT_NULL 链表的头节点,直接把数据插入这个头节点对应的区中即可,
如果该区的空间已经被用完,就把该节点移到 FULL 链表中


三 链表基节点

抛出问题,15个链表,如何找到某个链表的头/尾节点? Innodb设计 链表基节点 (List Base Node)  每个链表都有此基节点

List Length 表明该链表一共有多少节点

First Node Page Number First Node Offset 表明该链表的头节点在表空间中的位置。

Last Node Page Number Last Node Offset 表明该链表的尾节点在表空间中的位置。

链表小结

表空间是由若干个区组成的,每个区都对应一个 XDES Entry 的结构,

直属于表空间的区对应的 XDES Entry 结构可以分成 FREEFREE_FRAG FULL_FRAG 3个链表;

每个段可以附属若干个区,每个段中的区对应的 XDES Entry结构可以分成 FREENOT_NULL FULL 3个链表。

每个链表都对应一个 List Base Node 结构,这个结构里记录了链表的头、尾节点的位置以及该链表中包含的节点数。

正是因为这些链表的存在,管理这些区才变得容易


四 段的结构

段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念由若干个零散的页面以及一些完整的区组成。

像每个区都有对应的 XDES Entry 来记录这个区中的属性一样,InnoDB的设计者为每个段都定义一个 INODE Entry 结构来记录段中的数据

4.1 Segment ID

就是指这个 INODE Entry 结构对应的段的编号(ID)

4.2 NOT_FULL_N_USED

这个字段指的是 NOT_FULL 链表中已经使用了多少个页面 

4.3   3 List Base Node

段的FREE 链表 ,NOT_FULL 链表,FULL 链表定义了 List Base Node,

这样想查找某个段的某个链表的头节点和尾节点的时候,就可以直接到这个部分找到对应链表的 List Base Node

4.4 Magic Number

这个值是用来标记这个 INDEO Entry 是否已经被初始化了(初始化的意思就是把各个字段的值都填进去了)。如果这个数字是 97937874,表明该 INODE Entry 已经初始化,否则没有被初始化

4.5 Fragment Array Entry

前面强调过段是一些零散页面和一些完整的区的集合,每个Fragment Array Entry 结构都对应着一个零散的页面,这个结构一共4个字节,表示一个零散页面的页号


五 各类型页面详细情况

5.1 FSP_HDR 类型

第一个组的第一个页面,当然也是表空间的第一个页面,页号为0这个页面的类型是 FSP_HDR,它存储了表空间的一些整体属性以及第一个组内256个区的对应的 XDES Entry 结构

5部分组成

名称

中文名

占用空间大小

简单描述

File Header

文件头部

38字节

页的一些通用信息

File Space Header

表空间头部

112字节

表空间的一些整体属性信息

XDES Entry

区描述信息

10240字节

存储本组256个区对应的属性信息

Empty Space

尚未使用的空间

5986字节

用于页结构的填充,没啥实际意义

File Trailer

文件尾部

8字节

校验页是否完整


5.1.1 File Space Header用来存储表空间的一些整体属性的

名称

占用空间大小

描述

Space ID

4字节

表空间的 ID

Not Used

4字节

4个字节未被使用,可以忽略

Size

4字节

当前表空间占用的页面数

FREE Limit

4字节

尚未被初始化的最小页号,大于或等于这个页号的区对应的 XDES Entry 结构都没有被加入 FREE 链表

Space Flags

4字节

表空间一些占用存储空间比较小的属性 (表空间中与布尔类型相关的属性)

FRAG_N_USED

4字节

FREE_FRAG 链表中已使用的页面数量

List Base Node for FREE List

16字节

FREE 链表的基节点

List Base Node For FREE_FRAG List

16字节

FREE_FRAG 链接的基节点

List Base Node For FULL_FRAG List

16字节

FULL_FRAG 链表的基节点

Next Unused Segment ID

8字节

当前表空间中下一个未使用的 Segment ID (类似全局变量, 一个索引2个段, 每个段ID 唯一)

List Base Node for SEG_INODES_FULL List

16字节

SEG_INODES_FULL 链表的基节点

每个段对应一个INODES_Entry结构, 这些INODES_Entry会集中存放在类型为INODE的页中, 如果很多就需要多个INODE-> 形成SEG_INODES_FULL 链表—已经被INODES_Entry填满 无法存放过多的INODE Entry

List Base Node for SEG_INODES_FREE List

16字节

SEG_INODES_FREE 链表的基节点


5.1.2 XDES Entry 链表 (XDES Entry结构对应表空间一个区)

XDES Entry 就是在表空间的第一个页面中保存的。一个XDES Entry结构的大小是40字节,但是一个页面的大小有限,只能存放有限个XDES Entry结构,所以才把256个区划分成一组,在每组的第一个页面中存放256XDES Entry结构。因为每个区对应的XDES Entry结构的地址是固定的,所以访问这些结构的时候就比较方便


5.1.3 XDES 类型 (XDES 用来登记本组256个区的属性)

每个组的第一个页面只需要记录本组内所有的区对应的XDES Entry结构,不需要再记录表空间的属性了,为了和 FSP_HDR 类型做区别,把之后的每个分组的第一个页面的类型定义为 XDES,它的结构和 FSP_HDR类似

 

5.1.4 INODE 类型

第一个分组的第三个页面的类型是 INODE

InnoDB为每个索引定义了两个段,而且为某些特殊功能定义了些特殊的段,为每个段设计了一个 INODE Entry 结构,这个结构中记录了关于这个段的相关属性。

INODE类型的页就是为了存储 INODE Entry 结构而存在的

一个INODE 类型的页面是有这几部分组成的

名称

中文名

占用空间大小

简单描述

File Header

文件头部

38字节

页的一些通用信息

List Node For INODE Page List

通用链表节点

12字节

存储上一个INODE页面和下一个INODE页面的指针

INODE Entry

段描述信息

16320字节

具体的INODE Entry 结构

Empty Space

尚未使用空间

6字节

用于页结构的填充,没啥实际意义

File Trailer

文件尾部

8字节

校验页是否完整

 

List Node For INODE Page List

因为一个表空间中可能存在超过85个段,所以可能一个 INODE 类型的页面不足以存储所有的段对应的 INODE Entry 结构,所以就需要额外的 INODE 类型的页面来存储这些结构。为了方便管理这些 INODE 类型的页面,InnoDB将这些 INODE 类型的页面串联成两个不同的链表:

SEG_INODES_FULL 链表:该链表中的 INODE 类型的页面中已经没有空闲空间来存储额外的 INODE Entry 结构了。

SEG_INODES_FREE 链表:该链表中的 INODE 类型的页面中还有空闲空间来存储额外的 INODE Entry 结构。

这两个链表的基节点就存储在 File Space Header里面, 也就是说这两个链接的基节点的位置是固定的,所以访问起来很方便。以后每当新创建一个段(创建索引时就会创建段)时,都会创建一个 INODE Entry 结构与之对应,存储 INODE Entry 的大致过程如下:

先看SEG_INODES_FREE链表是否为空,如果不为空,直接从该链表中获取一个节点,也就相当于获取一个仍有空闲空间的 INDEO 类型的页面,然后把该 INODE Entry 结构放到该页面中。当该页面中无剩余空间时,就把该页放到SEG_INODES_FULL链表中。

如果SEG_INODES_FREE链表为空,则需要从表空间的 FREE_FRAG 链表中申请一个页面,修改该页面的类型为 INODE,把该页面放到 SEG_INODES_FREE 链表中,与此同时把该 INODE Entry 结构放入该页面


Segment Header 结构的运用

一个索引会产生两个段,分别是叶子节点段和非叶子节点段,而每个段都会对应一个 INODE Entry 结构,我们要想知道某个段对应哪个INODE Entry 结构,就需要找个地方记下来这个对应关系 INDEX 类型的页里的 Page Header 部分

名称

占用空间大小

描述

PAGE_BTR_SEG_LEAF

10字节

B+树叶子段的头部信息,仅在 B+树的根页定义

PAGE_BTR_SEG_TOP

10字节

B+树非叶子段的头部信息,仅在 B+树的根页定义

PAGE_BTR_SEG_LEAFPAGE_BTR_SEG_TOP都占用10个字节,它们其实对应一个叫 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

INODE Entry 结构在该页面中的偏移量


PAGE_BTR_SEG_LEAF记录着叶子节点段对应的 INODE Entry 结构的地址是哪个表空间的哪个页面的哪个偏移量,

PAGE_BTR_SEG_TOP记录着非叶子节点段对应的 INODE Entry 结构的地址是哪个表空间的哪个页面的哪个偏移量。

这样子索引和其对应的段的关系就建立起来了。不过需要注意的一点是,因为一个索引只对应两个段,所以只需要在索引的根页面中记录这两个结构即可


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。