【MySQL】InnoDB数据页结构

news2024/11/14 22:04:12

文章目录

  • 1. 前言
  • 2. 数据页结构
  • 3. 记录在页中的存储
  • 4. 记录头信息
  • 5. 页目录(Page Directory)
  • 6. 页面头部(Page Header)
  • 7.文件头部(Fiile Header)
  • 8. 文件尾部(File Trailer)

不知不觉2022年已经结束了,没想到时间过得那么快,在这里祝大家新年快乐。

1. 前言

页是InnoDB管理存储空间的基本单位。

InnoDB为了不同目的实现了多种的不同类型的页,比如存储表空间头部的页、存放INODE信息的页等等。

但是我们比较关心的应该是存放表中记录的页,官方把这种存放记录的页称为索引页。

为了方便理解,下面把索引页称为数据页。


2. 数据页结构

数据页大小为16KB,这16KB被划分成多个部分。

img

数据页被分为7个部分,各个部分是干啥用的?请看下图

image-20221231141908594


3. 记录在页中的存储

我们存储的记录是按照行格式存储在User Records部分

但是在一开始生成页的时候,并没有User Records部分,当插入一条记录的时候,会从Free Space部分申请一个记录大小的空间。

当Free Space空间完全被User Records部分代替完之后,就意味着这个页用完了,如果再插入一条数据,就需要申请新的页了。

img


4. 记录头信息

在【MySQL】InnoDB记录存储结构有详细说到记录有信息。

img

但是这里主要说的是记录头的信息,先建一个表

CREATE TABLE page_demo(
	c1 INT PRIMARY KEY,
	c2 INT,
	c3 VARCHAR(10000),
)CHARSET=ASCII ROW_FORMAT=COMPACT;

这是设置c1为主键,那么InnoDB就没有必要创建row_id列了。

并且指定了ASCII字符集以及COMPACT的行格式。

img

这一节主要讲述记录头信息的作用,因此可以简化一下行格式。

image-20221231143343770

往表中插入数据

mysql> INSERT INTO page_demo VALUES(1, 100, 'aaaa'), (2, 200, 'bbbb'), (3, 300, 'cccc'), (4, 400, 'dddd'); 
Query OK, 4 rows affected (0.00 sec) 

User Records部分的存储结构如下图所示

img

但是需要注意的是,这里把记录中的头信息和实际数据都用是十进制表示出来了,但是实际上是二进制位。

可以看见记录头有很多属性,那么各个属性代表什么呢?

  • delete_flag这个属性是标记当前记录是否被删除,占用1比特。
    • 值为0表示没有被删除,值为1表示记录被删除
    • 为什么被删除的记录还在页中呢?这是因为如果真实移除这些记录,需要在磁盘上重新排列其他记录,这样会带来型号消耗。
    • 所有被删除的记录会组成一个垃圾链表,记录这个链表占用的空间称为可重用空间。之后如果有新记录插入到表中,它们就可以覆盖被删除的这些记录占用的存储空间。
  • min_rec_flag:B+树每层非叶子节点中的最小的目录项都会添加该标记。
  • n_owned:记录了该组有几条记录
  • heap_no:一条记录在堆中的相对位置
    • 记录在User Records中是亲密无间地排列的,这种结构被称为堆。
    • 在页面前面的记录heap_no比较小,在页面后面的记录比较大。
    • 例如,前面插入的4条数据中,heap_no的值分别为2、3、4、5
    • 而0和1则是最小记录(Infimun记录)和最大记录(Supremum记录)的heap_no值,它们被称为虚拟记录或伪记录。Infimun记录Supremum记录这两条记录的构造十分简单,都是由5字节大小的记录头信息和8字节大小的一个固定单词组成的。由于其heap_no最小,所以这两个记录放在堆的最前面
    • image-20221231144558123
    • img
    • 这里说的记录的大小是指主键的大小。
    • 并且,heap_no是固定不变的,也就是值分配之后就不会发生改动了,即使被删除,值也不会发生变化。
  • record_type:这个属性表示当前记录类型。
    • 一共有4个类型,0表示普通记录,1表示B+树非叶子节点的目录项记录,2表示Infimum记录,3表示Supermum记录。
    • img
  • next_record:这个属性非常重要,它表示当前记录的真实数据到下一条记录的真实数据的距离。
    • 正数表示下一条记录在当前记录后面,负数表示下一条记录在当前记录前面。
    • 下一条记录并不是指插入顺序中的下一条记录,而是按照主键值由小到大的顺序排列的下一条记录。
    • 并且规定了Infimum记录的下一条记录就是本页中主键值最小的用户记录,本页主键值最大的记录的下一条记录就是Supremum记录。
    • img
    • 如果将第二条数据删掉,那么第二条记录的delete_flag就会被设置为1,并第二条记录的next_record变为0,第一条记录的next_record指向第三天记录
    • img
    • next_record的位置之所以在记录头和真实数据之间,**是因为这种向左读取就是记录头信息,向右读取就是真实数据。**前面说到变长字段长度列表和NULL值列表都是逆序存放的,这样可以使得记录中位置靠前的字段和它对应的字段长度信息在内存中距离更近,可以提高高速缓存命中率。
    • 如果将刚才删除的数据再次插入表中,会直接复用原来删除记录的空间。
    • img

5. 页目录(Page Directory)

如果想要查找某一条记录,并不会在链表中一个个遍历查找。

在设计InnoDB的时候,为我们的记录制作了一个类似图书目录的目录。

  1. 将所有正常的记录(包括Infimum和Supremum记录,但是不包括被删除的记录)划分为几个组
  2. 每个组的最后一条记录相当于“带头大哥”,其他记录相当于“小弟”,在“大哥”的n_owned记录该组有多少条记录。
  3. 将最后一条记录的地址偏移量单独拿出来,按顺序存储在靠近页尾的地方,这个地方就是页目录。页目录的这些地址偏移量称为槽,每个槽占用2字节。

比如page_demo表中有6条数据,就会被分成2组。

img

  • 注意最小和最大记录的头信息中的n_owned属性 最小记录的n_owned值为1,这就代表着以最小记录结尾的这个分组中只有1条记录,也就是最小记录本身。 最大记录的n_owned值为5,这就代表着以最大记录结尾的这个分组中只有5条记录,包括最大记录本身还有我们自己插入的4条记录。
  • 对于最小记录所在的分组只能有 1 条记录,最大记录所在的分组拥有的记录条数只能在 1~8 条件之间剩下的分组中记录的条数范围只能在是 4~8 条之间
  • 所以 最小记录的 n_owned 是 1, 当前最大记录的 n_owned 是 5img

那分组是这么分的呢?

  1. 在初始情况下,一个数据页中只有Infmum记录和Supremum记录这两条,它们分属于两个分组。页目录中也只有两个槽,分别代表Infmum记录和Supremum记录在页面中的地址偏移量。
  2. 之后每插入一条记录,都会从页目录中找到对应记录的主键值比待插入记录的主键值大并且差值最小的槽(从本质上来说,槽是一个组内最大的那条记录在页面中的地址偏移量,通过槽可以快速找到对应的记录的主键值),然后把该槽对应的记录的n_owned值加 1,表示本组内又添加了一条记录,直到该组中的记录数等于8个。
  3. 当一个组中的记录数等于8后,再插入一条记录,会将组中的记录拆分成两个组,其中一个组中 4条记录,另一个 5 条记录。这个拆分过程会在页目录中新增一个槽录这个新增分组中最大的那条记录的偏移量。

例如,再向表插入12条记录

image-20221231151540835

img

怎么查找记录呢?

初始情况下最低的槽就是low = 0, 最高的槽就是hight=4,比如要找主键为6的记录。

  1. 计算中间槽的位置:(0+4)/2等于2,查找槽2的对应的记录的主键值为8,由于8>6,所以设置hight=2,
  2. 重新计算中间槽位置:(0 + 2)/2等于1,查找槽1的队友的记录的主键值为4,由于4<6,所以设置low=1,hight不变。
  3. 因为hight - low的值为1,所以确定主键值为6的记录在槽2。
  4. 因此可以从槽2的最小记录开始遍历查找。
  5. 槽2对应的记录是改组的主键值最大的记录,那么怎么定位槽2的最小记录呢?很简单,由于槽之间是挨着的,所以很容易找到槽1的最大记录,而槽1的最大记录的下一条记录就是槽2的最小记录。

6. 页面头部(Page Header)

页面头部是存储书局页中记录的状态信息,比如数据页存储了多少条记录、Free Space在页面中的地址偏移量、页目录中存储了多少槽等。

image-20221231152338648

  • PAGE_DIRECTION:假如新插入的一条记录的主键值比上一条记录的主键值大,我们说这条记录的插入方向是右边,反之则是左边。用来表示最后一条记录插入方向的状态就是 PAGE_DIRECTION。
  • PAGE_N_DIRECTION:假设连续几次插入新记录的方向都是一致的,InnoDB会把沿着同一个方向插入记录的条数记下来,这个条数就用PAGE_N_DIRECTION状态表示当然,如果最后一条记录的插入方向发生了改变,这个状态的值会被清零后重新统计。

7.文件头部(Fiile Header)

文件头部描述了一些通用各个页的信息,比如页的编号,它的上下页是谁等等。

文件头部由固定38个字节组成。

image-20221231152605894

  • FIL_PAGE_SPACE_OR_CHKSUM:这个属性代表当前页面的校验和 (checksum)。啥是校验和?就是对于一个很长的字节串来说,我们会通过某种算法计算出一个比较短的值来代表这个很长的字节串,这个比较短的值就称为校验和。这样在比较两个很长的字节串之前,先比较这两个长字节串的校验和。如果校验和都不一样,则两个长字节串肯定是不同的,这样就省去了直接比较两个长字节串的时间损耗。
  • FILE_PAGE_TYPE:页的类型

image-20221231152845685

并且页是一个双向链表。

img


8. 文件尾部(File Trailer)

文件尾部是用来检测一个页是否完整,防止刷新的时有没有发生只刷新一部分的情况。

文件尾部由8字节组成,分为两个部分:

  • 前4字节代表页的校验和。这个部分与 File Header 中的校验和相对应。每当一个页面在内存中发生修改时,在刷新之前就要把页面的校验和算出来。因为 File Header 在页面的前边,所以 File Header 中的校验和会被首先刷新到磁盘,当完全写完后,校验和也会被写到页的尾部。如果页面刷新成功,则页首和页尾的校验和应该是一致的。如果刷新了一部分后断电了,那么 File Header 中的校验和就代表着已经修改过的页,而File Trailer 中的校验和代表着原先的页,二者不同则意味着刷新期间发生了错误
  • 后4字节代表页面被最后修改时对应的LSN的后4字节,正常情况下应该与 FileHeader 部分的FIL PAGE LSN的后4字节相同。

参考:

  • 《MySQL是怎样运行的:从根儿上理解 MySQL》
  • 【MySQL进阶】深入理解InnoDB数据页结构_小颜-的博客-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM调优相关说明

前言 其实听着JVM调优这个词有些高大上&#xff0c;但是等你真正了解了他的内在原理后&#xff0c;还是很容易的。再简单 JVM调优大致可分为如下&#xff1a; 解决JVM运行过程中的问题&#xff08;主要就是内存溢出的问题&#xff09;优化JVM运行时的环境&#xff0c;提高运…

多线程问题(四)

目录 一、常见的锁策略 1、乐观锁 VS 悲观锁 2、读写锁 VS 普通的互斥锁 3、重量级锁 VS 轻量级锁 4、挂起等待锁 VS 自旋锁 6、公平锁 VS 非公平锁 7、可重入锁 VS 不可重入锁 8、synchronized锁的性质 二、CAS 1、CAS的伪代码 2、CAS的应用 a、实现原子类…

【Spring系列】一篇文章开启你的 SpringBoot 之旅

SpringBoot 快速入门一. 环境搭建1.1 环境准备Java环境准备(本人是 JDK 1.8)开发工具 IntelliJ IDEAMaven (可使用 IntelliJ IDEA 自带)二. 快速开始2.1 新建项目打开IDEA 新建 SpringBoot 项目2.2 运行项目Spring Boot 项目运行分析尝试在浏览器中访问2.3 完成第一个接口新建c…

ArcGIS基础实验操作100例--实验30清除坐标系信息

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验30 清除坐标系信息 目录 一、实验背景 二、实验数据 三、实验步骤 方法一&#xff…

运维管理平台OEM定制集成开发,激发IT价值

对硬件设备商而言&#xff0c;借助优秀的网管、运维管理平台&#xff0c;可以形成完整的产品解决方案&#xff0c;直接提升产品的形象和适用范围。同时还可以通过网管、运维管理平台&#xff0c;切入到外围的产品及集成领域&#xff0c;并在用户后续的升级改造活动中占据有利位…

12.31日报

纠正前天的错误&#xff1a; 前天我写&#xff1a; 不知道在mapper中的增删改方法返回值int的值&#xff0c;和含义&#xff0c;在调用方法时也没有定义int来接参&#xff0c;都是直接调用。于是我定义int i&#xff0c;并打印输出&#xff0c;使用postman调用接口方法&#xf…

R语言hdnom包进行高维惩罚 Cox 回归模型绘制列线图-校准曲线-时间依赖ROC-外部验证

Hdnom包可以用于用于给高维数据构建Cox 模型、绘制列线图-校准曲线-时间依赖ROC-外部验证&#xff0c;而且Hdnom包简化了建模过程&#xff0c;带有自动选择变量功能&#xff0c;将用户从繁琐且容易出错的调参过程中解放出来. hdnom提供了多项自动调参和模型选择功能&#xff…

【OpenAI】基于 Gym-CarRacing 的自动驾驶项目 | 前置知识介绍 | 项目环境准备

猛戳&#xff01;跟哥们一起玩蛇啊 &#x1f449; 《一起玩蛇》&#x1f40d; &#x1f4ad; 写在前面&#xff1a; 本篇是关于多伦多大学自动驾驶专业项目 Gym-CarRacing 的博客。GYM-Box2D CarRacing 是一种在 OpenAI Gym 平台上开发和比较强化学习算法的模拟环境。它是流行…

jscharting.js v3.3.1.20220428 Crack

jscharting.js 3.3 版带来了主要的新组织结构图和甘特图扩展&#xff0c;包括甘特关键路径图、组织连接线样式和选择、仪表板小部件、象形图等等。图表渐变支持扩展到包括图标和动态点和系列渐变填充。 JSCharting 团队使用新功能、图表类型和图表小部件制作了超过 55 个高级示…

从发展的趋势来看,数字技术理应是产业互联网时代的驱动力

事实上&#xff0c;以往&#xff0c;我们所经历的那个互联网玩家频出的年代&#xff0c;其实就是一个以互联网技术为主导的年代。在那样一个年代里&#xff0c;互联网技术几乎是解决一切痛点和难题的万能解药&#xff0c;几乎是破解一切行业痛点和难题的杀手锏。任何一个行业&a…

【Java语言】—顺序结构、分支结构

流程控制语句 Java提供了一些流程控制语句&#xff0c;来控制程序的执行流程。 1.顺序结构 按照代码的先后顺序&#xff0c;以此执行程序。 2.分支结构 &#xff08;1&#xff09;if分支 根据判断的结果&#xff08;真或假&#xff09;决定执行某个分支的代码。 if分支有三…

Docker+Nginx打包部署前后端分离项目

DockerNginx打包部署前后端分离项目1、问题描述2、项目打包2.1 前端项目打包2.1.1 修改vue.config.js文件2.1.2 router配置中添加base属性2.1.3 打包前端项目2.2 后端项目打包2.3 将前端和后端的打包文件上传到服务器3 nginx反向代理配置4、后端通过Dockerfile打包成docker镜像…

目标检测-锚框

目标检测算法通常会在输入图像中采样大量的区域&#xff0c;然后判断这些区域中是否包含我们感兴趣的目标&#xff0c;并调整区域边界从而更准确地预测目标的真实边界框&#xff08;ground-truth bounding box&#xff09;。 不同的模型使用的区域采样方法可能不同。 这里我们介…

vue3 antd项目实战——Form表单的重置【使用resetFields()重置form表单数据、清空输入框】

vue3 ant design vue项目实战——Form表单【resetFields重置form表单数据】关于form表单的文章场景复现resetFields()重置表单数据项目实战关于form表单的文章 文章内容文章链接Form表单提交和校验https://blog.csdn.net/XSL_HR/article/details/128495087?spm1001.2014.3001…

十二、Kubernetes核心技术Service详解、实例

1、概述 我们都知道Kubernetes会为每个pod分配一个独立的IP&#xff0c;然而却存在如下问题&#xff1a; Deployment控制的3个pod&#xff0c;其中一个Pod出现问题&#xff0c;这个时候给销毁重新创建后Pod Ip会变化Pod IP 仅仅是集群内可见的虚拟IP&#xff0c;外部无法访问 …

AcWing的Linux基础课学习笔记(未学完)

目录版本B站试听课&#xff08;1.常用文件管理命令&#xff09;1.1文件系统1.2文件管理常用指令版本 服务器&#xff1a;Linux Ubuntu 20.04     我的笔记本&#xff1a;Acer Nitro AN515-55&#xff08;所以如果我要在AC Terminal里复制粘贴的话分别是&#xff1a;CtrlFnI…

autoload魔术方法的妙用

前言&#xff1a; __autoload魔术方法从PHP7.2.0开始被废弃&#xff0c;并且在PHP8.0.0以上的版本完全废除。取而代之的则是spl_autoload_register&#xff0c;但是本文还是研究__autoload。 什么是autoload魔术方法&#xff1f; 首先还是从官方手册中下手&#xff0c;了解a…

C++线程池的一种实现

线程池是实际开发中提高软件性能和稳定性的一种基本手段。可以想一下&#xff0c;如果程序中不用多线程&#xff0c;那执行效率会很低&#xff0c;如果运行线程太多&#xff0c;操作系统又吃不消&#xff0c;程序性能和稳定性会收到威胁。所以使用线程池技术诞生了&#xff0c;…

争做八桂好网民网络评选投票小程序投票的优劣微信怎么投票

用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务&#xff0c;很多用户都很喜欢“活动星投票”这款软件。“活动星投票”小程序在使…

【Linux】Linux进程的理解

如果不改变自己&#xff0c;就别把跨年搞的和分水岭一样&#xff0c;记住你今年是什么吊样&#xff0c;明年就还会是什么吊样&#xff01;&#xff01;&#xff01; 文章目录一、冯诺依曼体系结构&#xff08;硬件&#xff09;二、操作系统&#xff08;软件&#xff09;1.操作…