一条 INSERT 语句背后的秘密

MySQL关系型数据库NoSQL数据库

picture.image

快看这个宝藏网站(面试、工作内推、技术分享什么都有):http://www.susan.net.cn

你以为你写了一条 SQL,其实你是在和数据库的一整套存储机制打交道。

在这里插入图片描述
一、引言:懂记录结构,真的很重要!

💥 开篇三连击:

  • 当你敲下INSERT时,数据是在磁盘「盖房子」还是「搭积木」?
  • 行格式里藏着哪些「加密代码」?
  • 一条“莫名其妙”的慢查询,根源可能是行格式选错?

这些问题的答案,就藏在 InnoDB 的记录结构里。

我们在写 SQL 的时候,经常只关注“写对了没”、“跑起来没报错”。但真正理解 MySQL 的底层行为,往往要从一句简单的 INSERT 开始。

二、从一条INSERT语句开始说起

当我们执行INSERT INTO users (name, age,address) VALUES ('张三', 25,'北京.海淀');这条语句时,数据并不会直接 “一股脑” 地塞进磁盘。InnoDB 会按照特定的规则,将数据 “搭建” 成特定的结构,然后再存储到磁盘上。

为了更好地理解这个过程,我们先来对比一下行数据以及行结构。

假设我们有一张users表,包含id、name、age、address四个字段。

  
CREATE TABLEusers (  
    idINTUNSIGNEDNOTNULL AUTO\_INCREMENT COMMENT'主键ID',  
    nameVARCHAR(100) NOTNULLCOMMENT'用户姓名',  
    age INTUNSIGNEDCOMMENT'年龄',  
    address VARCHAR(255) COMMENT'地址',  
    PRIMARY KEY (id)  
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='用户信息表';  
  

当我们插入一条数据(1, '张三', 25,'北京.海淀')时,从表面上看,我们看到的行数据是这样的:

| id | name | age | address | | --- | --- | --- | --- | | 1 | 张三 | 25 | 北京海淀 |

然而在 InnoDB 中,一条数据并非简单存储,而是拆分成多个部分:记录头信息保存元数据,变长字段列表记录变长字段及长度,NULL 值列表标记哪些字段为 NULL。

InnoDB目前支持四种行格式:

  • COMPACT(最常用)
  • REDUNDANT(MySQL 5.0之前)
  • DYNAMIC(MySQL 5.7默认)
  • COMPRESSED(压缩格式)

COMPACT 行格式是最常用的“标准模板”,掌握它能帮助你理解 InnoDB 记录结构的核心。

三、COMPACT 行格式详细介绍:数据存储的 “标准模板”

废话不多说,直接看图:

picture.image

3.1 记录头信息:数据的 “身份证”

记录头信息仅占5字节,却包含记录类型、删除标记、B+树位置等关键信息,是记录的重要标识。

picture.image当我们执行DELETE语句删除一条记录时,InnoDB 并不会立即从磁盘上删除这条记录,而是在记录头信息中设置删除标记,后续再通过专门的机制进行清理。

| 字段 (Field) | 位数 (Bits) | 描述 (Description) | | --- | --- | --- | | 预留位1 | 1 | 保留位,目前没有用到。 | | 预留位2 | 1 | 保留位,目前没有用到。 | | delete_mask | 1 | 标记该记录是否被删除,1-是,0-否 | | min_rec_mask | 1 | 标记该记录是否是B+树叶子节点中最小的记录,1-是,0-否 | | record_type | 3 | 标记记录的类型。000表示普通记录,001表示最小值记录,010表示目录记录,011表示最大值记录。 | | n_owned | 4 | 表示当前记录拥有的记录数 | | heap_no | 13 | 标记当前记录在当前页面(Page)中的相对位置(槽号)。 | | next_record | 16 | 表示下一条记录的相对位置 | | 预留位2 | 1 | 保留位,目前没有用到。 |

3.2 变长字段列表:应对 “变化多端” 的数据

在实际应用中,很多字段的数据长度是不固定的,比如VARCHAR、TEXT、BLOB等类型的字段。变长字段列表就是为了应对这些 “变化多端” 的数据而设计的。它会记录哪些字段是变长的,以及它们的长度。

变长字段列表采用倒排的方式存储,也就是说,它从右往左存储每个变长字段的长度。

3.2.1 变长字段列表如何存储实际数据?

当执行插入语句INSERT INTO users VALUES(1, '张三', 25, '北京.海淀');时,我们来分析一下变长字段列表的存储方式。

a)、字段分析

  • id :INT 类型,固定长度 4 字节,不属于变长字段

  • name :VARCHAR (100),实际存储 ' 张三 ',UTF-8 编码下每个汉字占 3 字节,共 6 字节

  • age :INT 类型,固定长度 4 字节,不属于变长字段

  • address :VARCHAR (255),实际存储 ' 北京.海淀 ',共包含 5 个字符(2 个汉字、1 个点、2 个汉字),每个汉字 3 字节,点 1 字节,共 13 字节

    b)、变长字段列表的倒排存储

上面的例子中,有两个变长字段:name和address。它们的长度分别是 6 字节和 13 字节。根据倒排存储规则,变长字段列表会按照从右到左的顺序记录这些长度。

  • 表定义顺序是:name, address
  • 倒排后,存的时候顺序是:address, name

因此,变长字段列表的内容为:[13,6]。

picture.image

这些值并不是直接以十进制存入,而是编码成 1~2 字节的二进制形式(依字段长度大小决定)。

3.3 NULL 值列表:节省空间的 “小能手”

在 InnoDB 中,NULL 值列表是一种节省空间的巧妙设计。它不存储 NULL 的实际值,而是用每个字段对应的一位二进制位来标记:

  • 1 表示该字段为 NULL;
  • 0 表示不为 NULL。

在计算 InnoDB 记录结构中的 NULL 值列表时,只有那些“允许为 NULL”的字段才会被纳入统计。

以 users 表为例:

  • id 是主键,不能为 NULL;
  • name 被 NOT NULL 明确声明,也不能为 NULL;
  • age 和 address 没有限定 NOT NULL,默认是可以为 NULL 的。

所以,NULL 值列表中只包含 age 和 address 这两个字段的状态位。

picture.image

NULL 值列表的位顺序,是按照表结构中允许 NULL 字段的出现顺序排列的,且仅包含这些字段。

四、行溢出:当数据太大时会发生什么?

a)、为什么会出现行溢出?

InnoDB 的数据存储以 “页” 为基本单位,每页默认大小为 16KB。当我们插入的数据(如一篇几万字的文章、高清图片的二进制数据)长度超过一页能容纳的空间时,InnoDB 就会遇到 “空间不够用” 的难题。就像你想把 100 本书塞进只能装 50 本书的箱子,自然装不下。

b)、什么是行溢出?

为了解决上述问题,InnoDB 引入了行溢出机制:

  • 当数据过长时,它会把超出数据页容量的部分 “搬” 到额外的溢出页中存储;
  • 并在原数据页保留一个指向溢出页的指针(通常是20字节)。

这就好比把装不下的书先放在旁边的临时箱子,再在原本的箱子贴上标签注明 “其余书在隔壁箱”。

picture.image

行溢出虽解决大字段存储,但带来性能隐患,如查询慢、空间管理复杂、碎片增多。优化可从多方面入手:拆大字段表、选适配数据类型与行格式,控制字段长度,同时避免在大字段建索引,以此提升数据库性能。

五、结语:深入底层,才能掌控全局

数据库的 “高性能密码” 藏在底层结构里。从 INSERT 语句到磁盘存储,COMPACT 行格式的字段管理、行溢出的优化逻辑,都是提升数据库能力的关键。懂记录结构,才能在面试中从容应答,在优化时直击痛点。

记住:深挖底层原理,才能让技术成长 “知其所以然”。欢迎留言交流,一起解锁更多数据库奥秘!

最后欢迎加入苏三的星球,你将获得:商城微服务实战、AI开发项目课程、苏三AI项目、秒杀系统实战、商城系统实战、秒杀系统实战、代码生成工具、系统设计、性能优化、技术选型、底层原理、Spring源码解读、工作经验分享、痛点问题、面试八股文等多个优质专栏。

还有1V1答疑、修改简历、职业规划、送书活动、技术交流。

扫描下方二维码,即可加入星球:

picture.image

目前星球已经更新了5200+篇优质内容,还在持续爆肝中.....

星球已经被官方推荐了3次,收到了小伙伴们的一致好评。戳我加入学习,已有1700+小伙伴加入学习。

picture.image

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
字节跳动 NoSQL 的实践与探索
随着 NoSQL 的蓬勃发展越来越多的数据存储在了 NoSQL 系统中,并且 NoSQL 和 RDBMS 的界限越来越模糊,各种不同的专用 NoSQL 系统不停涌现,各具特色,形态不一。本次主要分享字节跳动内部和火山引擎 NoSQL 的实践,希望能够给大家一定的启发。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论