「mysql是怎样运行的」从一条记录说---InnoDB记录存储结构

news2024/11/14 15:24:01

「mysql是怎样运行的」从一条记录说—InnoDB记录存储结构

文章目录

  • 「mysql是怎样运行的」从一条记录说---InnoDB记录存储结构
    • 一、InnoDB页介绍
    • 二、InnoDB行格式
      • 2.1 COMPACT行格式
      • 2.2 REDUNDANT行格式
      • 2.3 溢出列
      • 2.4 DYNAMIC行格式和COMPRESSED行格式
    • 三、总结

一、InnoDB页介绍

InnoDB是一个把数据存储在硬盘的存储引擎,即使服务器重启,数据依然不会丢失,而真正的数据处理是发生在内存中的,所以InnoDB需要把硬盘上数据加载到内存中,然后在内存中进行各种数据处理,最终在某个时机把内存中的数据刷新到硬盘。而硬盘的处理速度是很慢很慢的,和内存差的太远了,如果InnoDB每次只从硬盘中读取一条数据,显然是不行的,速度会慢死,所以InnoDB会把数据分成若干页,以页作为内存和硬盘之间交互的基本单位,说的再直白点:InnoDB读取数据不是一行一行读,而是以页为最小单位读取数据。默认情况下,一页是16K,也就是InnoDB读取数据的数据大小至少是16K。当然这个值是可以被修改的,因为一般情况下,也没人会修改这个值,所以这里我就不说明应该怎么改了。


二、InnoDB行格式

我们平时是以记录为单位向表中插入数据的,记录在磁盘上的存放形式也被称为行格式记录格式

InnoDB 提供了4种行格式供我们选择,分别是Compact、Redundant、Dynamic和Compressed行格式,以后可能会有新的行格式出现,但是区别并不是很大。

我们建表的时候,可以指定某种行格式:

CREATE TABLE table_name (列信息) ROW_FORMAT=行格式名称 

也可以修改已经存在的表的行格式:

ALTER TABLE  table_name ROW_FORMAT=行格式名称 

准备工作

为了后面的故事可以顺利展开,我们先来建一张表:

CREATE TABLE  hero( `x` VARCHAR(10), `y` VARCHAR(10) NOT NULL, `z` CHAR(10), `t` VARCHAR(10) )CHARSET=ASCII, ROW_FORMAT=COMPACT; 

我建了一张表,指定的行格式是COMPACT,采用的字符集是ASCII,也就是我们的中文是无法存进去的,现在我要向这张表添加两行数据:

INSERT INTO hero(x, y, z, t) VALUES('a', 'bb', 'cccc', 'ddddd'), ('a', 'b', NULL, NULL); 

现在表中的数据是这样的:

表建好了,数据填充好了,下面我们就来分析下在COMPACT行格式下,数据是如何存储的吧。

2.1 COMPACT行格式

image-20230112223426271

其中COMPACT的行格式由记录的额外信息和记录的真实数据两部分组成组成。

1、记录的额外信息

  • 变长字段列表:在MySQL中一般有一些变长的类型,如VARCHAR(M),text,blob等,InnoDB会将非NULL的变长字段的字节长度按照列的顺序的逆序存储到变长字段列表中,而行中存储真实数据。对于变长字段是用两个字节来存储变长长度还是用1个字节存储遵循以下规则:如果该列能够存储的最大字节数(M(存储的最大字符数)*W(字符集中每个字符所占用的最大字节数))小于等于256时直接采用1个字节存储,如果大于256时,假设实际存储的长度L小于等于127时,便采用1个字节,否者用2个字节,因为此时如果是需要用1位来作为标志位标志是读取1个字节还是2个字节。除此之外,当某个字段的数据特别多的时候,可能采用溢出页来存储剩下的数据。由于每页最多为16KB即16384字节,所以两个字节一定能表示出该字段的长度。
  • NULL值列表:将可以将为NULL值的列按列的顺序的逆序存储到NULL值列表中,其中如果该位为NUll值,便将该位对应的值设置为1,并且高位补0。
  • 记录头信息:由5个字节固定表示,来描述记录的一些属性。如该记录是否被删除,是否是目录项等。

2、记录的真实数据

  • 对于记录的真实数据中除了显示出来的列之外,还有row_id,trx_id,roll_pointer三列隐藏列。

    列名作用
    row_id行ID唯一标识1行
    trx_id事务ID
    roll_pointer回滚指针

    注意:InnoDB中一定有主键,如果未人为设置了主键,便选取非空的唯一键作为主键,此时都不会添加row_id否者用row_id充当主键。

3、CHAR(M)列的存储格式

当CHAR(M)的字段采用变长编码时,也会将其在变长字段长度列表中记录该字段所占的字节数,但是如果采用定长编码时便不会。同时,如果CHAR(M)如果采用变长编码的形式,其中要求该字段至少占用M个字节。

2.2 REDUNDANT行格式

其中REDUNDANT没有COMPACT紧凑,在一般在MySQL5.0之前常使用。

image-20230112223942931

  • 字段长度偏移列表:该行格式会将该记录中所有的列,包括隐藏列的偏移量按逆序存储到字段长度偏移量列表中。一般该字段的长度为相邻两个偏移量之差。
  • 记录头信息:会有一个1byte_offs_flag来标记该偏移量存储是1个字节还是2个字节。
  • 1byte_offs_flag的选取:如果记录总长度小于等于127遍直接用1个字节存储,否者用2个字节存储。其中为什么是127,因为会在偏移量中选取最高位作为NULL值的标记位。
  • NULL值处理:偏移量中选取最高位作为NULL值来标记该字段是否为NULL,并且如果字段是定长类型,比如char(M),则直接将其设置为M*一个字符需要的最大字节数(如utf8为3)个字节,并且将存储实际数据的地方初始化为0,这样可以直接在原位置更新;对于变长类型,便不会在真实数据处记录数据。

2.3 溢出列

当某列的数据超过临界点时,称之为溢出列,此时COMPAT记录格式会记录该列的前768个字节,然后用20字节用来指向存储剩余数据的地址,其中剩余数据是以链表的形式存储在其他页中。

2.4 DYNAMIC行格式和COMPRESSED行格式

其中DYNACMIC格式和COMPACT格式类似,但是在处理溢出列的时候,他不会存储前768个字节,而是只存储20个字节的指针。COMPRESSED则会采用压缩算法来使得存储空间更小。


三、总结

image-20230113143945794


参考

第五节:从一条记录说起——InnoDB记录结构

第4章 从一条记录说起—InnoDB记录存储结构

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

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

相关文章

字节终面,一道Linux题难住我了

以下是一道难道系数中高并且高频出现的linux面试题,题目具体要求如下: linux面试题: 某文件有多列数据,空格隔开,统计第n列单词,打印出现频率最高的5个单词。 解答这道面试题需要用到3个linux命令&#xff…

Spring @Asyn使用不当引起OOM

问题 生产环境偶尔出现pod重启,排查后发现是因为发生了OOM,才导致pod重启的。 查看日志,有如下错误 报错信息中描述为无法创建新的本地线程,根据堆栈的上线文,发现是因为异步接口使用了SimpleAsyncTaskExecutor执行器…

x79主板M.2无法识别固态硬盘

问题描述: 这几天在装电脑,买了块M.2接口固态硬盘。装上去始终无法读取到硬盘,一开始以为是寨板Bios问题不支持M.2的设备。更新了最新的BIOS然后还是没有识别出来,然而将日常用的电脑PM510硬盘装上发现可以识别,而且日常用电脑也…

KeePass敏感信息明文传输漏洞复现 (CVE-2023-24055)

一、漏洞描述 漏洞简述 KeePass 是一款免费的开源密码管理器,可帮助您以安全的方式管理您的密码。您可以将所有密码存储在一个数据库中,该数据库由一把万能钥匙锁定。因此,您只需记住一个主密钥即可解锁整个数据库。数据库文件使用目前已知…

python元类编程

1.1.propety动态属性 在面向对象编程中,我们一般把名词性的东西映射成属性,动词性的东西映射成方法。在python中他们对应的分别是属性self.xxx和类方法。但有时我们需要的属性需要根据其他属性动态的计算,此时如果直接使用属性方法处理&…

复习C语言过程中的总结与思考(万字长文 + 思维导图,强烈建议收藏)

内容长文,多图预警!!!一、C语言的数据类型和读取标准1. C语言中整数型**常量**的数据类型为int类型,例子如下:2. C语言中浮点数型常量的数据类型为double类型二、C语言中的输入输出及位运算符1、scanf函数缓…

关于微服务架构的思考

引言 众所周知微服务已经经过了炒作周期的兴奋阶段,但并不是说它现在过时了。微服务架构算是笔者过往印象比较深的项目之一。并且,即使作为行业的最佳实践,但也能看到各种各样失败的案例。所以今天想跟大家分享一下关于微服务相关深度思考的…

【服务器数据恢复】多块磁盘离线导致RAIDZ崩溃的数据恢复案例

服务器数据恢复环境: SUN ZFS系列某型号存储阵列; 40块磁盘组建的存储池(其中4块磁盘用作全局热备盘),池内划分出若干空间映射到服务器使用; 服务器使用Windows操作系统。 服务器故障: 服务器在…

一文讲解thop库计算FLOPs问题

问题 计算模型的FLOPs及参数大小 FLOPS是处理器性能的衡量指标,是“每秒所执行的浮点运算次数”的缩写。 FLOPs是算法复杂度的衡量指标,是“浮点运算次数”的缩写,s代表的是复数。 一般使用thop库来计算,GitHub: h…

c++ 那些事 笔记

GitHub - Light-City/CPlusPlusThings: C那些事 1. ① extern extern关键字,C语言extern关键字用法详解 如果全局变量不在文件的开头定义,其有效的作用范围只限于其定义处到文件结束。如果在定义点之前的函数想引用该全局变量,则应该在…

45个写规范代码的小技巧

目录 1、规范命名 2、规范代码格式 3、写好代码注释 4、try catch 内部代码抽成一个方法 5、方法别太长 6、抽取重复代码 7、多用return 8、if条件表达式不要太复杂 9、优雅地参数校验 10、统一返回值 11、统一异常处理 12、尽量不传递null值 13、尽量不返回null值…

BN、SyncBN、IN、LN、GN学习记录

1 BatchNormBN的原理BN是计算机视觉最常用的标准化方法,它沿着N、H、W维度对输入特征图求均值和方差,随后再利用均值和方差来归一化特征图。计算过程如下图所示,1)沿着通道维度计算其他维度的均值;2)沿着通…

numpy入门

目录: numpy数据类型numpy维度numpy常用操作 numpy数据类型 numpy的数据类型是numpy.ndarray,它不同于python的array.array,ndarray可以处理多维数据。ndarray的常见属性有dtype,shape,size等,在进行一些…

接口自动化测试框架-Python+Requests+Yaml

零代码极限封装的【接口自动化测试框架】,目前已经完全能够实现真正的零代码落地并在企业中推广。其中用到的最核心的封装技术如下:核心技术1.热加载封装,是全网最早应用于自动化测试框架的封装技术。2.Requests统一请求封装3.接口关联封装以及接口关联封…

微服务03 分布式搜索引擎 elasticsearch ELK kibana RestAPI RestClient

分布式搜索引擎01-- elasticsearch基础0.学习目标1.初识elasticsearch1.1.了解ES1.1.1.elasticsearch的作用elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容例如:在GitHub搜索代码…

【Python】带你进入字典的世界

如约而至,紧接着上一期文章,小编将会陆续把全套的Python笔记将依次发放给大家,便于大家学习Python、期末备考、巩固基础等(这几期是公众号小插曲,后期发放编程技术的话主要还是会围绕Java来展开~感谢大家支持)字典字典是Python内置…

鸿翼企业网盘 激活企业协作办公

信息化的发展,使企业网盘成为了许多企业必备的“数字基础设施”。鸿翼企业网盘,让网盘不仅是数据存储的“仓库”,更是数据利用的“中枢”,以网盘为载体,激活企业“协作力”。 企业网盘起初是为了解决企业内数据统一存储…

基于SpringBoot+MyBaits_Vue+ElementUi构建项目

基于SpringBootMyBaits_VueElementUi构建项目 1.Spring Boot 后台搭建 1.1.项目初始化 前期准备:maven,jdk(1.8),idea 1.1.1.下载地址 Spring官方提供了Springboot自定义配置地址,可依照相关选项搭建所…

6.4 实战:实现 Web API 版本控制

第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战:实现 Web API 版本控制 6.4 实战:实现 Web API 版本控制 如果业务需求变更,Web API 功能发生变化时应该如何处理呢&…

易错:List中的add方法添加对象时出现重复的问题

错误&#xff1a; 用list存储User对象信息&#xff0c;当存储多个对象时&#xff0c;发现存储的数据都是一样的 之前代码&#xff1a; User user new User();List<User> list new ArrayList<>();for (int i 0; i < 5; i) {user.setName("Tom"i);…