0
点赞
收藏
分享

微信扫一扫

三、mysql磁盘管理:mysql数据是怎么组织的?

水沐由之 2022-03-12 阅读 84

一、InndoDB 逻辑存储结构

我们建一张 tb_user 表,就会生成一个名为 tb_user.ibd 的表空间文件

         为了保证顺序IO,表空间被划分为多个连续的数据区,256个连续的数据区称为一个数据区组,一个数据区又由64个连续的数据页组成,数据页包含数据行。

一个数据页大小为 16 KB

一个数据区大小为 64 * 16 KB = 1 MB

一个数据区组大小为 256 * 1 MB = 256 MB

        在 InnoDB 中有个参数 innodb_file_per_table ,默认值为 on,表示每张表的数据单独放到一个表空间。

        常见的段有数据段,索引段,回滚段。数据即索引,那么数据段即为B+树的叶子节点,索引段即为B+树的非索引节点。

        段是一个逻辑概念,段最小申请内存为1MB,为了防止空间浪费,先用32个页大小的碎片页来存放数据,在使用完这些页后才是64个连续页的申请。

        页是 InnoDB 磁盘管理的最小单位,大小为16KB,和操作系统的页(4KB)概念不同。

        表空间第一个数据区组的第一个数据区前3个数据页是固定的,存放一些描述信息

                (1) FSP_HDR:存放表空间和这一组数据区的信息

                (2) IBUF_BITMAP:这一组数据页的 insert buffer 数据信息

                (3) INODE:存放特殊信息

        表空间里的其他各组数据区,每一组数据区的第一个数据区的头两个数据页,都是存放特殊信息

                (1) XDES:记录这一组数据区的信息

                (2) IBUF_BITMAP:这一组数据页的 insert buffer 数据信息

二、InnoDB 数据页结构

File Header:文件头,记录页的一些头信息

Page Header:数据页头,记录数据页的状态信息

Supremum和Infimum:最大记录最小记录,限定数据记录的边界

User Records:数据行,实际存储行记录的内容

Free Space:空闲区域,数据页中剩余可插入数据的空间

Page Directory:数据页目录,存放数据记录的相对位置,有时候这些记录指针称为槽(Slots),我们通过B+树索引并不能找到具体的一条记录,只能找到记录所在的数据页,然后通过数据页目录进行二叉查找找到最终的数据

FileTrailer:文件尾部,校验页是否完整的写入磁盘

 三、InnoDB 行记录格式

这里只介绍 compact 行记录格式

变长字段长度列表:字段类型为 varchar 的字段长度,按照列顺序逆序排列

null值列表:记录字段是否为null,0:非null,1:null,占用1个字节

数据头: 40位,固定占用5个字节

隐藏列:

  • DB_ROW_ID:如果 Innodb 没有指定主键,会生成一个rowid列,6字节
  • DB_TRX_ID:事务ID,6字节
  • DB_ROLL_PTR:回滚指针,7字节

在InnoDB中,每张表都有一个主键,如果再创建表时没有显示的定义主键,则InnoDB会按如下方式选择或创建主键:

  • 首先判断是否有非空的唯一索引,如果有,则该列即为主键
  • 如果不符合上述条件,InnoDB自动创建一个6字节大小的指针

当有多个非空唯一索引时,InnoDB 存储引擎将选择建表时第一个定义的非空唯一索引为主键

行溢出

        一个数据页大小为16KB,如果有一个表里有这样一个字段 varchar(65532) ,表示可以存放65532个字符,也就是65532个字节,远大于16KB,说明一个数据页放不下这一行数据。就需要将数据拆分到多个数据页中存放。每行数据都有个指针指向其他数据页中的溢出行。

如图所示,通过多个数据页来存储一行数据,当要读取这一行数据时,就需要加载多个数据页到缓冲池中了。

  • Compact格式与Redundant格式,在处理行溢出时,真实数据中只保存 768 字节的前缀,之后的数据都是偏移量,指向溢出页
  • Compressed格式与Dynamic格式,在处理行溢出时,数据完全溢出,在数据页只存放20字节的指针,实际的数据都存放在Off Page中

四、示例

下面通过一个示例说明:

我们创建一张 innodb 存储引擎的表,表结构如下:

create table tb_user (
      id varchar(8) not null,
      name  varchar(10),
      gender char(1),
      job  varchar(12),
      address  varchar(20)
);

往表中插入几行数据:

insert into tb_user values('1001','melon',null,'chengxuyuan',null);

insert into tb_user values('1002','zhangsan',null,null,'test');

通过 select * from tb_user 能够查询到这样一张视图

数据库数据:

id

name

age

address

job

1001

melon

NULL

chengxuyuan

NULL

1002

zhangsan

NULL

NULL

test

使用16进制编辑器查看 tb_user.ibd 文件,高亮部分即为行存储的格式,我们看到2行数据是连续存储的,第二行数据紧挨着第一行数据

第一行数据高亮如下

0b 05 04 :变长字段长度,逆序

0a :null值列表

00 00 10 00 30:数据头

00 00 00 00 29 73:RowId

00 00 00 00 3d a5:事务ID

c8 00 00 01 7b 01 10:回滚指针

31 30 30 31 1001

6d 65 6c 6f 6e melon

63 68 65 6e 67 78 75 79 75 61 6e chengxuyuan

1001字符串长度:4,用16进制表示:0x04
melon字符串长度:5,用16进制表示:0x05
chengxuyuan字符串长度:11,用16进制表示:0x0b
倒序展示为: 0b 05 04

允许为null值的有4个字段,2个null,2个非null,null用1表示
null值列表按顺序表示为:0101,倒序排列为:1010,
16进制表示为 0a

举报

相关推荐

0 条评论