Innodb如何实现表--下篇

news2024/11/20 20:26:37

Innodb如何实现表--下篇

  • Innodb数据页结构
    • File Header
    • Page Header
    • Infimum和Supremum Record
    • User Records和Free Space
    • Page Directory
    • File Trailer
    • 实例分析


Innodb数据页结构

Innodb数据页由以下7个部分组成:

  • File Header(文件头)
  • Page Header(页头)
  • Infimun和Supremum Records
  • User Records(用户记录,行记录)
  • Free Space(空闲空间)
  • Page Directory(页目录)
  • File Trailer(文件结尾信息)

在这里插入图片描述


File Header

File Header是所有类型页通用的头信息,共占用38字节:

在这里插入图片描述
Innodb存储引擎页主要有下面几种类型:
在这里插入图片描述


Page Header

PageHeader是数据页特有的,专门用来记录数据页的状态信息,共占用48字节:

在这里插入图片描述


Infimum和Supremum Record

在InnoDB存储引擎中,每个数据页中有两个虚拟的行记录,用来限定记录的边界。Infimum记录是比该页中任何主键值都要小的值, Supremum指比任何可能大的值还要大的值。这两个值在页创建时被建立,并且在任何情况下不会被删除。

在Compact行格式和Redundant行格式下,两者占用的字节数各不相同。下图显示了Infimum和Supremum 记录。
在这里插入图片描述


User Records和Free Space

User Record就是之前讨论过的部分,即实际存储行记录的内容。再次强调,InnoDB存储引擎表总是B+树索引组织的。

Free Space很明显指的就是空闲空间,同样也是个链表数据结构。在一条记录被删除后,该空间会被加入到空闲链表中。

在这里插入图片描述


Page Directory

Innodb一个数据页中会存放很多条记录,我们之前讲行格式时提到过。记录的头信息中有一个next_record属性指向下一条记录的位置,因此数据页中多条记录通过单链表的形式串连起来:
在这里插入图片描述
链表的特点就是不支持随机遍历,也不支持二分快速查找,如果我们想要快速定位一条记录,那么只能将整个链表进行一遍遍历,因此对于Innodb来说,必须要优化这个问题。

为了支持随机遍历和二分快速查找,Innodb推出了页目录的概念,页目录相当于一个连续的数组,数组中的元素被称为槽,每个槽代表一段范围内的用户记录,并且指向该范围内的最后一条记录。

n_owned属性指示当前槽指示的范围里面包含了多少用户记录,并且Innodb规定伪记录Infimum的n_owned值总是为1,记录Supremum的n_owned的取值范围为[1,8],其他用户记录n_owned的取值范围为[4,8]。当记录被插人或删除时需要对槽进行分裂或平衡的维护操作。

因此,此时在某个数据页内定位一条记录时,首先通过二分查找定位到某个槽,再通过槽定位到那段范围内的记录,由于记录是通过单链表形式串连起来,所以下面就是遍历这个链表定位到目标记录所在位置。

n_owned不能设置过大,否则当通过槽定位到一组记录时,单链表遍历耗时就会增加; 如果n_owned设置过小,那么二分查找次数会增加,并且页目录也会占据更多空间。


File Trailer

为了检测页是否已经完整地写人磁盘 (如可能发生的写人过程中磁盘损坏、机器关机等) ,InnoDB存储引擎的页中设置了File Trailer部分。

File Trailer只有一个 FIL_PAGE_END_LSN 部分,占用8字节。前4字节代表该页的checksum值,最后4字节和File Header中的FIL_PAGE_LSN相同。

在这里插入图片描述

File Header组成图

将这两个值与File Header 中的 FIL_PAGE_SPACE_OR_CHKSUMFIL_PAGE_LSN 值进行比较,看是否一致(checksum的比较需要通过InnoDB的checksum函数来进行比较,不是简单的等值比较),以此来保证页的完整性(not corrupted)。


在默认配置下,InnoDB存储引擎每次从磁盘读取一个页就会检测该页的完整性,看页是否发生Corrupt,这就是通过File Trailer部分进行检测,而该部分的检测会有一定的开销。用户可以通过参数innodb_checksums来开启或关闭对这个页完整性的检查。

MySQL 5.6.6版本开始新增了参数innodb_checksum_algorithm,该参数用来控制检 测 checksum函数的算法,默认值为crc32,可设置的值有:innodb、crc32、none、strict innodb、strict_crc32、strict_none。
在这里插入图片描述

innodb为兼容之前版本InnoDB页的checksum检测方式,crc32为MySQL 5.6.6版 本引进的新的checksum算法,该算法较之前的innodb有着较高的性能。但是若表中所有页的checksum值都以strict算法保存,那么低版本的MySQL数据库将不能读取这些页。none表示不对页启用checksum检查。

strict_*正如其名,表示严格地按照设置的checksum算法进行页的检测。因此若低版本MySQL数据库升级到MySQL 5.6.6或之后的版本,启用strict_crc32将导致不能读取表中的页。启用strict_crc32方式是最快的方式,因为其不再对innodb和crc32算法进行两次检测。故推荐使用该设置。若数据库从低版本升级而来,则需要进行mysql_upgrade操作。
在这里插入图片描述


实例分析

光说不看假把戏,我们这里实操一番,先搞个表,再搞点数据:

CREATE DATABASE `test`;

USE `test`;

drop table if exists t;

create table t (
    a int unsigned not null auto_increment,
		b char(10),
		primary key(a)
)engine=innodb charset=utf8;

DELIMITER $$

CREATE PROCEDURE load_t(count int unsigned)

BEGIN

set @c=0;
WHILE @c<count DO
   INSERT into t 
	 SELECT NULL,REPEAT(char(97+RAND()*26),10);
	 SET @c=@c+1;
END WHILE;
end;
$$

DELIMITER ;

call load_t(100);

select a,b from t limit 10;

我们通过py_innodb_page_info工具来分析t.idb文件:

在这里插入图片描述
可以发现第四个页是数据页,然后通过hexdump来分析t.idb文件,打开整理得到的十六进制文件,数据页从0x0000c000(16KB*3=0xc000)处开始,得到以下内容:
在这里插入图片描述
先分析File Header的前面38个字节:
在这里插入图片描述

  • db d5 06 1c : 数据页的Checksum值
  • 00 00 00 03: 页的偏移量,从0开始
  • ff ff ff ff: 前一个页,因为当前只有一个数据页,所以为0xffffffff
  • ff ff ff ff:后一个页,因为当前只有一个数据页,所以为0xffffffff
  • 00 00 00 00 00 d4 b5 ec: 页的LSN
  • 45 bf: 页类型,0x45bf代表数据页
  • 00 00 00 00 00 00 00 00: 该值仅在系统表空间定义,代表文件至少被更新到了LSN值,对于独立表空间来说,该值为0
  • 00 00 00 4a: 表空间的SPACE ID

接着分析56字节的page header部分:
在这里插入图片描述

  • 页目录槽数: 00 1a --> 26个槽
  • PAGE_HEAD_TOP: 0d c0,代表空闲空间开始位置的偏移量,即0xc000+0xdc0=0xcdc0处开始

在这里插入图片描述

可以观察这个位置,发现这确实是最后一行的结束,接下去的部分都是空闲空间了。

  • PAGE_N_HEAP=0x8066,当行记录格式为Compact时,初始值为0x0802;当行格式为Redundant时,初始值是2。其实这些值表示页初始时就已经有Infinimun和Supremum的伪记录行,0x8066-0x8002=0x64,代表该页中实际的记录有100条记录。
  • PAGE_FREE=0x0000代表可重用的空间首地址,因为这里没有进行过任何删除操作,故这里的值为0。
  • PAGE_GARBAGE=0x0000代表删除的记录字节为0,同样因为我们没有进行过删除,所以这里的值依然为0。
  • PAGE_LAST_INSERT=0X0DA5,表示页最后插入的位置的偏移量,即最后插入位置应该在0xc0000+0x0da5=0xcda5处:
    在这里插入图片描述
    可以看到的确是最后插入a列值为100的行记录,但是这次直接指向了行记录的内容,而不是指向行记录的变长字段长度的列表位置。
  • PAGE_DIRECTION=0x0002,因为通过自增长的方式进行行记录的插入,所以PAGE_DIRECTION的方向是向右,为0x00002。
  • PAGE_N_DIRECTION=0x0063,表示一个方向连续插入记录的数量,因为我们是自增长的方式插入了100条记录,因此该值为99。
  • PAGE_N_RECS=0x0064,表示该页的行记录数为100,注意该值与PAGE_N_HEAP的比较,PAGE_N_HEAP包含两个伪行记录,并且是通过有符号的方式记录的,因此值为0x8066。
  • PAGE_LEVEL=0x00,代表该页为叶子节点。因为数据量目前较少,因此当前B+树索引只有一层。B+数叶子层总是为0x00。
  • PAGE_INDEX_ID=0x000000000000001ba,索引ID。

在这里插入图片描述
上面就是数据页的Page Header部分了,接下去就是存放的行记录了,前面提到过InnoDB存储引擎有两个伪记录,用来限定行记录的边界,接着往下看:

在这里插入图片描述
观察0xc05E到0xc077,这里存放的就是这两个伪行记录,在InnoDB存储引擎中设置伪行只有一个列,且类型是Char(8)。伪行记录的读取方式和一般的行记录并无不同,我们整理后可以得到如下结果:

在这里插入图片描述
然后来分析 infimum行记录的 recorder header部分,最后两个字节位001c表示下一个记录的位置的偏移量,即当前行记录内容的位置0xc063+0x001c,即0xc07f。
在这里插入图片描述

Compact行格式复习

0xc07f应该很熟悉了,之前分析的行记录结构都是从这个位置开始,如:
在这里插入图片描述
可以看到这就是第一条实际行记录内容的位置了,整理后我们可以得到(跳过前面头信息等字节):

00 00 00 01 -->因为每位建表时设置了主键,这里的ROWID即为列a的值1
00 00 00 00 14 8f ---> 事务ID
bd 00 00 01 35 01 10 --> 回滚指针
78 78 78 78 78 78 78 78 78 78 --> b列的值

通过 Recorder Header的最后两个字节记录的下一行记录的偏移量就可以得到该页中所有的行记录,通过Page Header的PAGE_PREV和PAGE_NEXT就可以知道上个页和下个页的位置,这样InnoDB存储引擎就能读到整张表所有的行记录数据。


最后分析 Page Directory。前面已经提到了从0x0000ffc4到0x0000fff7是当前页的

Page Directory,如下:

在这里插入图片描述
需要注意的是,Page Directory是逆序存放的,每个槽占2字节,因此可以看到0063是最初行的相对位置,即0xc063;0070就是最后一行记录的相对位置,即0xc070。我们发现这就是前面分析的Infimum和Supremum的伪行记录。

Page Directory 槽中的数据都是按照主键的顺序存放的,因此查询具体记录就需要通过部分进行。前面已经提到InnoDB存储引擎的槽是稀疏的,故还需通过 Recorder Header的n_owned进行进一步的判断,如InnoDB存储引擎需要找主键a为5的记录,通过二叉查找PageDirectory的槽,可以定位记录的相对位置在00e5处,找到行记录的实际位置0xc0e5。
在这里插入图片描述
可以看到第一行的记录是4,不是我们要找的6,但是可以发现前面的5字节的Record Header为04 00 28 00 22。找到4~8位表示n_owned值得部分,该值为4,表示该记录有4个记录,因此还需要进一步查找,通过 recorder header 最后两个字节的偏移量0x0022找到下一条记录的位置0xc107,这才是最终要找的主键为5的记录。

Compact行格式中记录头信息如下:
这里是引用


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

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

相关文章

Abaqus二次开发:局部坐标系的建立与应用

问题描述 在单向复材中&#xff0c;纤维的力学性能往往是横观各向同性的&#xff0c;于是需要规定材料方向。 通常需要新建局部坐标系用于材料方向的定义&#xff0c;而在实际建立坐标系中&#xff0c;坐标系会储存在对应的Part下&#xff1a; mdb.models[‘Model-1’].parts[…

GraphQL基础使用--mongoDB数据库操作

GraphQL hello world 首先我们要安装好执行GraphQL的环境 因为其是运行在node服务器端的&#xff0c;所以我们要安装 express express-graphql graphql mongoose 安装好后的package.json文件是这个样子的 其次我们就要开始配置端口为3000的node服务器 const express requir…

Leetcode---2.两数之和

目录题目分析链表最终代码实现&#xff08;内含注释&#xff09;题目 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和…

护眼灯对眼睛真的有作用吗?一文了解市面上的护眼灯是否真的管用

我们都知道&#xff0c;现在越来越多的人开始使用护眼台灯照明了&#xff0c;不为别的&#xff0c;只为眼睛健康&#xff0c;所以同样的也有许多人质疑护眼灯是否真的对眼睛有效果&#xff0c;今天就来聊聊护眼灯是否真的有护眼作用。 在我看来&#xff0c;人体眼睛看任何事物…

TS201的通过外部中断IRQ0控制DMA传输(含参考代码)

外部中断控制DMA传输 DMA的原理就不多说了&#xff0c;之前的文章里有写。 电路中的Interrupt Pin ADSP-TS201 EZ-KIT Lite评估板上每片DSP含有4个外部中断(IRQ3–0 )&#xff0c;其中IRQ0接到了一个按键上&#xff08;SW4和SW5&#xff09;。 当按键按下时&#xff0c;表现…

西湖论剑 Flagshop 分析复现

前言 比赛时候没能做出来&#xff0c;其实这道题就是一道pwn题。后面与p w n师傅讨论分析EXP分析还原了解题过程。学到了很多&#xff0c;也希望分享给大家。 任意文件读取 抓包或者看源码就会发现有一个SSRF&#xff0c;但是没有权限读flag&#xff0c;测试发现存在一个readf…

全网惟一面向软件测试人员的Python基础教程-为什么要学Python

全网惟一面向软件测试人员的Python基础教程 起点&#xff1a;python软件测试实战宝典》目录 第一章 为什么软件测试人员要学习Python 文章目录全网惟一面向软件测试人员的Python基础教程前言一、Python是什么&#xff1f;二、为什么要学二、测试人员如何学二、怎么从0开始学Py…

旅行路线可视化研究与实现(Java+Android+Eclipse实现的旅游APP)

目 录 1 概论 1 1.1 研究现状 1 1.2 系统开发意义 1 1.3 系统开发背景 2 2 开发环境以及相关技术 5 2.1 Eclipse 5 2.2 Adroid 5 2.2.1 基本概念 5 2.2.2 简介 6 2.2.3 系统架构 6 2.2.4 四大组件 7 2.3 Java语言 7 2.4 SQLite 7 2.4.1 简介 7 2.4.2 架构 7 2.4.3 特点 8 2.5 F…

《Redis 深度历险:核心原理与应用实践》学习

1、Redis的5种基础数据结构 Redis的5种基础数据结构&#xff1a;string (字符串&#xff09;、list (列表 &#xff09;、hash (字典&#xff09;、 set (集合&#xff09;、zset (有序集合&#xff09;。 Redis所有的数据结构都以唯一的key字符串作为名称&#xff0c; 然后通…

基于粒子群优化算法的边缘链接用于边缘检测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

艾美捷FLIVO探针:用于细胞活体凋亡检测,助力科研!

细胞凋亡在胚胎发育、造血、免疫系统的成熟以及维护正常组织和器官的细胞恒定与生长平衡&#xff0c;乃至机体衰老方面都起着重要作用。因此&#xff0c;有关凋亡的研究在临床和基础等各个领域已经广泛开展,凋亡细胞的检测方法显得非常重要。 FLIVO(荧光活体)是一种强大的无创检…

首个搭载8MP摄像头的单SoC行泊一体方案来袭,已拿下多家车企定点

行泊一体正在进入前装规模化上车的关键周期&#xff0c;但同时产品的升级战争也在全面爆发。 《高工智能汽车》了解到&#xff0c;国内领先的智能驾驶技术供应商——AutoBrain重磅推出了国内首个搭载800万像素摄像头的单SoC行泊一体方案。据悉&#xff0c;这是全球量产首发搭载…

dubbo消费者访问不到docker里面的生产者

版本 dubbo3.0.7 Docker version 20.10.21, build baeda1f docker zookeeper lastest 背景 一个dubbo的项目&#xff0c;生产者和消费者之间使用zookeeper管理。 现将消者和zookeeper部署到了docker中&#xff0c;二者使用的都是桥接网络。 消费者仍然在idea中编写逻辑。 服…

正片工艺、负片工艺,这两种PCB生产工艺的差异到底是什么?

在前文《什么是加成法、减成法与半加成法&#xff1f;》中&#xff0c;我们提到&#xff1a;减成法仍为当前PCB生产工艺的主流&#xff0c;那么&#xff0c;其中的两大代表工艺——正片工艺、负片工艺&#xff0c;又是怎样的呢&#xff1f; 请看下图&#xff1a; 当然&#xf…

一起用Go做一个小游戏(下)

打包资源使用file2byteslice包我们可以将图片和config.json文件打包进二进制程序中&#xff0c;之后编译生成一个二进制程序。然后拷贝这一个文件即可&#xff0c;不用再拷贝图片和其他配置文件了。golang有很多第三方包可以将打包资源&#xff0c;原理其实很简单——读取资源文…

面试官:使用 RocketMQ 怎么进行灰度发布?

今天来聊一聊 RocketMQ 的灰度方案。 灰度发布是指在黑与白之间&#xff0c;平滑过渡的一种发布方式。在大流量的系统中&#xff0c;如果一次升级改造范围比较大&#xff0c;或者影响内容不太确定&#xff0c;一般会采用切量的方式进行升级&#xff0c;这样可以减少生产变更带…

面试官:MySQL 中 varchar(n) 中 n 最大取值为多少?

前置知识 要回答这个问题&#xff0c;首先我们得先知道 MySQL 存储一条记录的格式长什么样子。 以 Compact 行格式作为例子&#xff0c;它长这样&#xff1a; 可以看到&#xff0c;一条完整的记录分为「记录的额外信息」和「记录的真实数据」两个部分。 这里重点讲讲记录的…

探究L298N模块烧毁的原因

目录 基础介绍 代码思路 基础介绍 L298N电机驱动版主要由两个核心组件构成&#xff1a; L298N 驱动芯片78M05 稳压器型号&#xff1a; L298N封装&#xff1a; Multiwatt15V 描述&#xff1a;电源电压&#xff1a;4.5V~46V 特性&#xff1a;过流保护(OCP)&#xff1b;过热保…

在线教程 | 用「网红项目」DeepSOCIAL 进行社交距离监测

By 超神经 内容一览&#xff1a;YOLO v4 是一个实时的、高精度的目标检测模型&#xff0c;本教程将详细讲解如何基于 YOLO v4 和 SORT 算法&#xff0c;实现在多目标条件下的人群距离检测。 关键词&#xff1a;YOLO v4 SORT 多目标检测 新冠疫情爆发初期&#xff0c;「保持…

VSCODE安装ChatGPT插件

zh1&#xff1a;首先在插件商店搜索ChatGPT中文版 然后点击安装就可以 2&#xff1a;chatGPT插件目前需要登陆账号才能使用&#xff0c;官方介绍下一个版本会有升级(不需要登陆) a:前往 ChatGPT 并登录或注册。 首先要先注册&#xff0c;注册的时候邮箱号可以填国内的也可以用…