当前位置: 首页 > article >正文

【Innodb阅读笔记】之行记录格式(Redundant)

一、Redundant 行记录格式

        在 MySQL 5.0 版本之前,Innodb 采用 Redundant 这种行记录存储方式。MySQL 之所以仍保留对 Redundant 的支持,关键在于要确保与旧版本页格式的兼容性,以此维系数据库在不同版本更迭期间的平稳过渡与数据连贯性。值得一提的是,Redundant 行记录格式自身还具备不少独特优点,使其在当时发挥了重要作用。

        其一,Redundant 格式有着出色的稳定性。在早期 MySQL 数据库应用场景尚不算复杂、硬件资源相对有限的环境下,它能够稳健地承载各类数据存储任务,极少出现因存储格式自身问题引发的数据异常或丢失情况,为数据库的稳定运行筑牢根基,让企业用户放心地将关键业务数据托付其中。

        其二,数据解析简易。从存储结构来看,虽说它与 Compact 行记录格式有所不同,但正是因为自身记录头信息及固定的存储规则,让数据解析环节相对直截了当。开发人员、数据库管理员在进行数据提取、排查问题或是执行低层级的数据操作时,能够迅速依据其格式特点定位到目标数据,节省大量时间成本,提升运维与开发效率。

        其三,Redundant 行记录格式兼容性极佳。它不仅适配旧版本 MySQL 的诸多特性与功能模块,对于一些老旧的第三方数据库工具、插件,同样能够无缝对接。这意味着企业无需大规模更换周边技术生态,就能持续利用既有资源开展业务,降低技术升级的成本与风险。

       再看 Redundant 行记录格式的具体构成,它与广为人知的 Compact 行记录格式相比,二者有着显著差异。Compact 行记录格式的开头部分是字段长度偏移列表,该列表别具一格,依照列顺序的逆序进行排列。具体而言,若字段长度小于 255 字节,仅用 1 字节予以表示;一旦长度超出 255 字节,便会启用 2 字节来精准描述。

        第二部分是记录头信息,这部分稳稳占据 6 字节的存储空间。其中,n_fields 值是重中之重,它精准记录了一行当中列的数量,以 10 位二进制数来承载信息,理论上最大值可达 1023,这一数值设定恰好揭示了 MySQL 数据库每行最多支持 1023 个列的底层缘由;另有一个 1byte_offs_flag,该标识肩负特殊使命,专门用于界定偏移列表究竟占用 1 字节还是 2 字节,为后续数据读取、解析提供关键指引。下面是记录头信息具体解析:

名称大小描述
()1未知
()1未知
deleted_flag1该行是否已被删除
min_rec_flag1存储目录项记录中主键值最小的目录项记录置为1,其它情况都置0.
n_owned4页目录中每个组的最后一条记录会存储该组的记录数,作为n_owned字段。值的关注的是,在mysql中最小记录是一组,普通记录与其它记录是一组,因此最小记录中n_owned属性是1,最大记录的n_owned值是5.
heap_no13当前页中该记录的排序位置
n_fields10 记录中页的数量
1byte_offs_flag1偏移列表为 1 字节还是 2 字节
next_record16页中 下一条记录的相对位置
total40 合计

二、实践

1. 创建表结构并导入对应数据

# mytest 表结构 
mysql> show create table mytest \G;
*************************** 1. row ***************************
       Table: mytest
Create Table: CREATE TABLE `mytest` (
  `t1` varchar(10) DEFAULT NULL,
  `t2` varchar(10) DEFAULT NULL,
  `t3` char(10) DEFAULT NULL,
  `t4` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
1 row in set (0.00 sec)


# 根据 mytest 表 创建表结构
create table mytest2 engine = Innodb row_format = redundant
as select * from mytest


# 表定义 
mysql> show table status like 'mytest2' \G;
*************************** 1. row ***************************
           Name: mytest2
         Engine: InnoDB
        Version: 10
     Row_format: Redundant
           Rows: 8
 Avg_row_length: 2048
    Data_length: 16384
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2024-12-09 10:32:41
    Update_time: 2024-12-09 10:32:41
     Check_time: NULL
      Collation: utf8mb4_general_ci
       Checksum: NULL
 Create_options: row_format=REDUNDANT
        Comment:
1 row in set (0.00 sec)

2. 找到 mytest2.ibd 文件,并使用二进制文件打开

# 查找到 C07D位置
23 20 16 14 13 0c 06     # 边长字段列表
00 00 10 0f 00 ba        # record header
00 00 00 00 02 09        # rowid
00 00 00 00 05 5f        # transactionID
da 00 00 01 59 01 10     # roll point
61 
62 62
62 62 20 20 20 20 20 20 20 20
63 63 63

# 解析第一行 变长字段列表  23 20 16 14 13 0c 06 
# 转换为 06 0c 13 14 16 20 23 分别代表:
# 第一列长度 6,第二列长度 6 = 0x0C - 0x06 第三列长度 7 = 0x13 - 0x0C
# 第四列长度 1 = 0x14 - 0x13,第五列长度 2 = 0x16 - 0x14
# 第六列长度 10 = 0x20 - 0x16,第七列长度 3 = 0x23 - 0x20

# 解析第二行

# 00 转换为 二进制 0000 0000,前两位不介绍,第三位表示当前记录没有被删除, 第四位表示当前记录不是最小记录, 
# 后四位表示 当前组有多少数据,记录在最后一行,当前不是最后一行数据,所以为 0 

# 00 10 0f 转换为二进制 为 0000 0000 0001 0000 0000 1111
# 对于前 13 位 0000 0000 0001 0,表示排序顺序为 10
# 对于 14 到 23 位 000 0000 111 记录列的数量,转换为 10进制为 7 位,正好对应边长字段个数
# 最后 1 为 是否为 1 字节,当前为 1,表示列的长度用 1 字节表示

# 0c 06 表示下一行的相对位置 0xC089 + 0x00BA - 0x008A (当前数据的偏移地址) = 0xC0B9

# 后面 7 列为正常数据列 其中 3 行为隐藏列,4 行为定义数据列

# 第二行数据  
23 20 16 14 13 0c 06     # 边长字段列表
00 00 18 0f 00 ea        # record header
00 00 00 00 02 0a        # rowid
00 00 00 00 05 5f        # transactionID
da 00 00 01 59 01 1e     # roll point

# transactionID 为什么和第一条数据一样 
# 因为 他们是在一个事物提交的, 所以事务是一样的
# 注意 第三条数据的位置计算 0xC0B9 + (0x00EA - 0x00BA (当前数据的偏移地址)) = 0xC0B9  + 0x30 = C0E9

# 第三行数据 null 数据 
21 9e 94 14 13 0c 06     # 边长字段列表
00 00 20 0f 01 18        # record header
00 00 00 00 02 0b        # rowid
00 00 00 00 05 5f        # transactionID
da 00 00 01 59 01 2c     # roll point 
64
00 00 00 00 00 00 00 00 00 00
66 66 66

# 解析第一行 变长字段列表  21 9e 94 14 13 0c 06
# 转换为 06 0c 13 14 94 9e 21 分别代表:
# 第一列长度 6,
# 第二列长度 6 = 0x0C - 0x06 
# 第三列长度 7 = 0x13 - 0x0C
# 第四列长度 1 = 0x14 - 0x13,
# 第五列固定长度 null 变成 0x94,边长列表记录为 0x94 固定写死,行中数据使用00占用
# 第六列长度 10 = 0x9e - 0x94,记录当前行占用多少字节,但是具体行不存储数据
# 第七列长度 3 = 0x21 - 0x14 - 0x0A(第二行数据 null占用字节 )


        当前表 mytest2 的字符集为 Latin1,每个字符最多占用 1 字节,若用户将表的字符集改为 utf8,第三列固定长度类型长度不再是占用10字节,而是 10 * 3 = 30 字节, 所以在 Redundant 下 char 可能是占用存储最大字节数。


http://www.kler.cn/a/429253.html

相关文章:

  • PyTorch 神经协同过滤 (NCF) 推荐系统教程
  • Qt Quick 和 Qt Designer
  • 如何异地远程访问本地部署的Web-Check实现团队远程检测与维护本地站点
  • 如何有效防止和解决IP劫持问题
  • APISQL在线一键安装教程
  • citrix netscaler13.1 重写负载均衡响应头(基础版)
  • GPU渲染图形的步骤和流程
  • SAP 汇率维护OB08和对应配置,以及取值BAPI<转载>
  • Weiss 机器人电动夹爪,重塑工业自动化精密操作
  • Linux:信号的预备和产生
  • 【AI 探索之旅:从基础认知到前沿突破的深度游二】学习大模型前的准备
  • NLP-中文分词
  • Git仓库移除文件的暂存和修改
  • 【计算机网络】实验18:动态主机配置协议DHCP的作用
  • 前端工程化面试题目常见
  • ros项目dual_arm_pick-place(urdf文件可视化查看)
  • 设计模式----链式设计
  • 如何在 JavaScript 中设置定时器?
  • 2024-09 GESP C++ 一级试题及答案解析
  • 使用Jackson库的ObjectMapper类将Java对象转换为JSON格式
  • 数据结构之五:排序
  • ubuntu18.04升级到20.04
  • Web后端开发技术:RESTful 架构详解
  • 聚观早报 | 华为Mate 70开售;小米15 Ultra影像大升级
  • HDFS的架构优势与基本操作
  • vivado中,generate output product 和Create HDL wrapper的作用