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

一、Innodb行记录格式

        innodb 存储引擎同大多数数据库一样,记录是以行的形式存储的。这意味着页中保存的一行行的数据。在 mysql 5.7 版本中,默认格式为 Dynamic,可以通过命令查看当前表的行格式,其中 row_format 表示当前表行记录格式类型:

# 查询 数据表 z 的行格式 默认为 dynamic
mysql> show table status like 'z' \G;
*************************** 1. row ***************************
           Name: z
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 3
 Avg_row_length: 5461
    Data_length: 16384
Max_data_length: 0
   Index_length: 16384
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2024-12-05 10:19:54
    Update_time: 2024-12-05 10:25:48
     Check_time: NULL
      Collation: utf8mb4_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

二、Compact 行记录格式

        compact 行记录格式是在 mysql 5.0 中引入的,其设计目的是高效的存储数据,简单来说,一个页中存放的行数据越多,其性能就越高。图中显示了 compact 行记录的存储方式。

        从图中可以观察到,compact 行记录格式的首部是一个非 null 变长字段长度列表,并且是按照列的逆序放置的,其长度为:

        若列的长度小于255字节,用 1 字节表示

        若大于255个字节,则用两字节表示

        边长字段的长度最大不能超过两个字节,这是因为 mysql 数据库中 varchar 类型的最大长度限制为 65535。

        变长字段之后的第二个部分是 null 标识位,该标识指示了该行数据是否有 null 值,有则用 1 表示,该部分所占字节应该为1字节。

        接下来的部分是记录头信息,固定占用 5 字节,每位含义如下:

        

compact 记录头信息
名称大小描述
()1 未知
()1 未知
deleted_flag1该行是否已被删除
min_rec_flag1存储目录项记录中主键值最小的目录项记录置为1,其它情况都置0.
n_owned4页目录中每个组的最后一条记录会存储该组的记录数,作为n_owned字段。值的关注的是,在mysql中最小记录是一组,普通记录与其它记录是一组,因此最小记录中n_owned属性是1,最大记录的n_owned值是5.
heap_no13当前页中该记录的排序位置
record_type3记录类型 0 表示普通类型,1表示B+树的非叶子节点 2,2表示最小记录,3表示最大记录。
next_record16页中 下一条记录的相对位置
total40 合计

        最后部分是实际存储每个列的数据,需要注意的是 null 不占该部分任何空间,每行除了用户定义的列外,还有两个隐藏列,事务id列,回滚指针列,分别为 6 字节和 7 字节大小,若没有定义主键列,还会增加一个 6 字节大小的 rowid 列。

        接下来用一个具体示例来分析 compact 行记录的内部格式:

# 创建表结构
mysql> create table mytest (
    ->  t1 varchar(10),
    ->  t2 varchar(10),
    ->  t3 char(10),
    ->  t4 VARCHAR(10)
    -> ) engine=innodb charset=latin1 row_format=compact;
Query OK, 0 rows affected (0.03 sec)


# 插入数据
mysql> INSERT INTO mytest VALUES ('a', 'bb', 'bb', 'ccc');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO mytest VALUES ('d', 'ee', 'ee', 'fff');
Query OK, 1 row affected (0.00 sec)
mysql> insert into mytest values ('d', null, null, 'fff');
Query OK, 1 row affected (0.00 sec)


# 用 notepad++ 打开 mytest.ibd 文件,需要下载 hex-editor 插件, 定位到C078位置
# 第一行数据 
03 02 01                      # 变长字段列表 逆序
00                            # null 标识位
00 00 10 00 2c                # record header 
00 00 00 00 02 01             # rowid
00 00 00 00 05 56             # transactionid
d1 00 00 01 50 01 10          # roll pointer
61                            # 第一列数据
62 62                         # 第二列数据
62 62 20 20 20 20 20 20 20 20 # 第三列数据
63 63 63                      # 第四列数据
# 第一行 变长字段列表为逆序状态,转换回来为01 02 03,
#     对应第一列、第二列、第4列长度分别为、1字节、2字节、3字节

# 第二行 null 标识位 目前没有null的列 所以为 00

# 第三行为 record header 占用5字节
#    第1个字节转换为二进制 0 0 0 0 0 0 0 0
#        未知 0 
#        未知 0
#        deleted_flag 0 改行未删除
#        min_rec_flag 0 该行不是最小记录
#        n_owned      0000  该组拥有的记录数 不记录在当前节点
#    第2个和第3个字节转为二进制 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
#        heap_no 0 0 0 0 0 0 0 0 0 0 0 1 0 排在第一行数据
#        record_type 0 0 0 表示普通记录
#    第3个和第5个字节 next_record 002C 下一行的记录为当前位置 + 002C
#        C080 + 002C = C0AC 下一行数据的next_record位置



# 第二行数据
03 02 01                      # 边长字段列表 逆序
00                            # null 标识位
00 00 18 00 2b                # record header 
00 00 00 00 02 02             # rowid
00 00 00 00 05 57             # transactionid
d2 00 00 01 51 01 10          # roll pointer
64                            # 第一列数据
65 65                         # 第二列数据 
65 65 20 20 20 20 20 20 20 20 # 第三列数据
66 66 66                      # 第四列数据
# 第一行 变长字段列表为逆序状态,转换回来为01 02 03,
#     对应第一列、第二列、第4列长度分别为、1字节、2字节、3字节

# 第二行 null 标识位 目前没有null的列 所以为 00

# 第三行为 record header 占用5字节
#    第1个字节转换为二进制 0 0 0 0 0 0 0 0
#        未知 0 
#        未知 0
#        deleted_flag 0 改行未删除
#        min_rec_flag 0 该行不是最小记录
#        n_owned      0000  该组拥有的记录数 不记录在当前节点
#    第2个和第3个字节转为二进制 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0
#        heap_no 0 0 0 0 0 0 0 0 0 0 0 1 1 排在第二行数据
#        record_type 0 0 0 表示普通记录
#    第3个和第5个字节 next_record 002B 下一行的记录为当前位置 + 002B
#        C0AC + 002B = C0D7 下一行数据的next_record位置


# 第三行数据
03 01                         # 边长字段列表 逆序
06                            # null 标识位
00 00 20 00 1F                # record header
00 00 00 00 02 03             # rowid             
00 00 00 00 05 58             # transactionid
d3 00 00 01 52 01 10          # roll pointer
64                            # 第一列数据
66 66 66                      # 第四列数据
# 第一行 变长字段列表为逆序状态,转换回来为01  03,
#     对应第1列、第4列长度分别为1字节、3字节

# 第二行 null 标识位 06 转换为二进制 0110
#    第二列、第三列 为 null

# 第三行为 record header 占用5字节
#    第1个字节转换为二进制 0 0 0 0 0 0 0 0
#        未知 0 
#        未知 0
#        deleted_flag 0 改行未删除
#        min_rec_flag 0 该行不是最小记录
#        n_owned      0000  该组拥有的记录数 不记录在当前节点
#    第2个和第3个字节转为二进制 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
#        heap_no 0 0 0 0 0 0 0 0 0 0 1 0 0 排在第 3 行数据
#        record_type 0 0 0 表示普通记录
#    第3个和第5个字节 next_record 001F 下一行的记录为当前位置 + 001F
#        C0D7 + 001F = C0F6 下一行数据的next_record位置

# 当我们在插入 5 条数据
mysql> insert into mytest values ('d', null, null, 'fff');
Query OK, 1 row affected (0.00 sec)

mysql> insert into mytest values ('e', null, null, 'ggg');
Query OK, 1 row affected (0.00 sec)

mysql> insert into mytest values ('h', null, null, 'lll');
Query OK, 1 row affected (0.00 sec)

mysql> insert into mytest values ('m', null, null, 'nnn');
Query OK, 1 row affected (0.01 sec)

mysql> insert into mytest values ('o', null, null, 'ppp');
Query OK, 1 row affected (0.00 sec)

# 解析一下第 4 条数据
03 01                         # 边长字段列表 逆序
06                            # null 标识位
04 00 28 00 1F                # record header
00 00 00 00 02 04             # rowid             
00 00 00 00 05 59             # transactionid
d4 00 00 01 53 01 10          # roll pointer
64                            # 第一列数据
66 66 66                      # 第四列数据
# 重点看一下 record header 第一个字节 04 其中 n_owned 占用4位等于4
#  表明当前数据为当前组的最后一条数据,其中这个组包含4条数据


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/932038.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

交易所 Level-2 历史行情数据自动化导入攻略

用户部署完 DolphinDB 后,需要将历史股票数据批量导入数据库,再进行数据查询、计算和分析等操作。DolphinDB 开发了 ExchData 模块,主要用于沪深交易所 Level-2 行情原始数据的自动化导入,目前已支持的数据源包括: 沪…

加载内核映像文件

将kernel转换成elf文件格式,不能直接从loader直接跳转到0x100000,需要解析,提取出代码和数据出来,放到0x10000(64kb)的位置,1M的位置只是存放elf文件的位置。 4.10加载内核映像文件2 common/el…

【数字电路与逻辑设计】实验一 序列检测器

文章总览:YuanDaiMa2048博客文章总览 【数字电路与逻辑设计】实验一 序列检测器 一、实验内容二、设计过程(一)作出状态图或状态表(二)状态化简(三)状态编码 三、源代码(一&#xff…

怎么实现邮件营销自动化?

邮件营销能够出色地帮助我们与客户建立良好关系。无论是新客户还是老客户,都可以通过邮件来达成较为良好的客户关系。然而,从消费者的角度来看,每个人都有自己独特的习惯和特点,没有人希望收到千篇一律、营销意味过重的邮件。因此…

【LeetCode: 203. 移除链表元素 + 链表】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

【opencv入门教程】12. 矩阵初始化

文章选自: 一、 数据类型 建立矩阵必须要指定矩阵存储的数据类型,图像处理中常用的几种数据类型如下:包括数据位深度8位、32位,数据类型U:uchar、F:float型以及通道数C1:单通道、C3:三通道、C4&#xff…

Jupyter Notebook认识、安装和启动以及使用

Jupyter Notebook认识、安装和启动以及使用 Jupyter Notebook认识、安装和启动以及使用 Jupyter Notebook认识、安装和启动以及使用一、认识Jupyter Notebook1.1 Jupyter Notebook概述1.2 Jupyter Notebook 重要特性(1)交互式代码执行(2)支持多种编程语言(3)富文本编辑(4)代码高…

SQL语句中AND与OR操作符的优先级问题

在SQL中,当AND和OR操作符同时出现时,优先级的处理可能会导致查询结果与预期不符。为了说明这一问题,我们可以看一个实际的例子。 假设需要查询价格在10美元及以上,且由DLL01或BRS01制造的所有产品。可以使用如下SQL语句&#xff…

FreeRTOS实现UART通信

串口通信 速战速决形式,大家走一遍就通; 本次实验验证: 配置文件 4、打开CubeMX 5、选择芯片型号,然后点击开始项目 6、配置时钟 配置烧录引脚,与FreeRTOS系统时钟 选择FreeRTOS 这里已经默认有一个任务&…

FaRM译文

No compromises: distributed transactions with consistency, availability, and performance Aleksandar Dragojevic, Dushyanth Narayanan, Edmund B. Nightingale, Matthew Renzelmann, Alex Shamis, Anirudh Badam, Miguel Castro Microsoft Research 目录 摘要 1. 引…

Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】

anaconda可以提供多个独立的虚拟环境,方便我们学习深度学习(比如复现论文); Pycharm编辑器可以高效的编写python代码,也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程: 1.Anaconda安装 下载Ana…

Angular由一个bug说起之十一:排序之后无法展开 Row

问题现象 在使用 Material Table 时,排序功能触发了一个奇怪的 Bug:表格的 Row 无法展开。最终排查发现,问题的根源在于 trackBy 的错误使用。trackBy 方法接受两个参数:index(数据索引)和 row(…

【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug

created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区,Zotero 中文维护小组,Zotero 插件,Zotero 中文 CSL 样式 数…

【React】React常用开发工具

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、React DevTools二、Redux DevTools三、Create React App 前言 React 是一种用于构建用户界面的流行 JavaScript 库,由于其灵活性、性能和可重用…

Thonny IDE + MicroPython + ESP32 + GY-302 测量环境中的光照强度

GY-302是一款基于BH1750FVI光照强度传感器芯片的模块。该模块能够直接测量出环境中的光照强度,并将光照强度转换为数字信号输出。其具体参数如下表所示。 参数名称 参数特性 测量范围 0-65535 LX 测量精度 在环境光下误差小于20%,能够自动忽略50/60…

华为HCIP AI EI Developer总结和备考建议

华为HCIP AI EI Developer总结和备考建议 最近空余时间考了一个华为的HCIP认证,属于AI方向的四个其中一个,这个主要侧重于机器学习和深度学习的基础知识,比较偏理论。 一、备考时间 根据华为官方建议,培训时长是9天,…

Jenkins 的HTTP Request 插件为什么不能配置Basic认证了

本篇遇到的问题 还是因为Jenkins需要及其所在的OS需要升级,升级策略是在一台新服务器上安装和配置最新版本的Jenkins, 当前的最新版本是: 2.479.2 LTS。 如果需要这个版本的话可以在官方站点下载,也可以到如下地址下载&#xff1…

运费微服务和redis存热点数据

目录 运费模板微服务 接收前端发送的模板实体类 插入数据时使用的entity类对象 BaseEntity类 查询运费模板服务 新增和修改运费模块 整体流程 代码实现 运费计算 整体流程 总的代码 查找运费模板方法 计算重量方法 Redis存入热点数据 1.从nacos导入共享redis配置…

Linux-USB驱动实验

USB 是很常用的接口,目前大多数的设备都是 USB 接口的,比如鼠标、键盘、USB 摄像头等,我们在实际开发中也常常遇到 USB 接口的设备,本章我们就来学习一下如何使能 Linux内核自带的 USB 驱动。注意!本章并不讲解具体的 …

Linux系统下安装配置 Nginx 超详细图文教程

一、下载Nginx安装包 nginx官网:nginx: downloadhttp://nginx.org/en/download.html找到我们所需要版本,把鼠标移动到上面,右键打开链接进行下载 或者如果Linux联网,直接在Linux服务上使用wget命令把Nginx安装包下载到/usr/local/…