mysql 页和叶子页_一看就懂的:MySQL数据页以及页分裂机制,别在说不会了

本文详细介绍了MySQL数据页和数据区的概念,指出数据页是存储数据的基本单位,而数据区是由一组连续的数据页组成。讨论了数据页分裂的问题,特别是在自定义非递增主键索引时可能导致的页分裂情况,以及如何通过分裂保持B+Tree的有序性。此外,解释了这样的数据组织方式有利于数据的管理和内存中的高效加载。

下面我们就一起看下,究竟什么是MySQL的数据页、数据区等概念。

二、数据页长啥样?

数据页长下面这样:

7bb93146ec9a

image.png

三、什么是数据区?

在MySQL的设定中,同一个表空间内的一组连续的数据页为一个extent(区),默认区的大小为1MB,页的大小为16KB。16*64=1024,也就是说一个区里面会有64个连续的数据页。连续的256个数据区为一组数据区。

于是我们可以画出这张图:

7bb93146ec9a

image

从直观上看,其实不用纳闷为啥MySQL按照这样的方式组织存储在磁盘上的数据。

这就好比你搞了个Java的封装类描述一类东西,然后再相应的给它加上一些功能方法,或者用golang封装struct去描述一类对象。最终的目的都是为了方便、管理、控制。

约定好了数据的组织方式,那MySQL的作用不就是:按照约定数据规则将数据文件中的数据加载进内存,然后展示给用户看,以及提供其他能力吗?

四、数据页分裂问题

假设你现在已经有两个数据页了。并且你正在往第二个数据页中写数据。

关于B+Tree,你肯定知道B+Tree中的叶子结点之间是通过双向链表关联起来的。

在InnoDB索引的设定中,要求主键索引是递增的,这样在构建索引树的时候才更加方便。你可以脑补一下。如果按1、2、3...递增的顺序给你这些数。是不是很方便的构建一棵树。然后你可以自由自在的在这棵树上玩二分查找。

那假设你自定义了主键索引,而且你自定义的这个主键索引并不一定是自增的。

那就有可能出现下面这种情况 如下图:

7bb93146ec9a

image

假设上图中的id就是你自定义的不会自增的主键

然后随着你将数据写入。就导致后一个数据页中的所有行并不一定比前一个数据页中的行的id大。

这时就会触发页分裂的逻辑。

页分裂的目的就是保证:后一个数据页中的所有行主键值比前一个数据页中主键值大。

经过分裂调整,可以得到下面的这张图。

7bb93146ec9a

image

<think>我们参考用户提供的引用内容,聚焦于MySQL如何将表文件拆分为数据页的存储机制。用户的问题明确要求解释“MySQL表文件拆分为数据页机制”,因此我们需要结合InnoDB引擎的表空间结构数据页设计来回答。根据引用内容:-引用[1]提到:InnoDB引擎使用表空间(如系统表空间、独立表空间)来管理数据,表数据存储在中。-引用[2]指出:InnoDB以(通常16KB)作为磁盘内存交互的基本单位,数据页是存放表中数据记录的。-引用[3][4]详细描述了数据页的内部结构,包括行格式的组成部分。因此,回答将围绕以下核心点展开:1.表空间与数据文件的关系(宏观存储结构)2.数据页的物理划分(16KB的固定大小)3.数据页的内部结构(7个组成部分,特别是UserRecords部分)4.数据行如何存储在数据页中(行格式与记录存储)5.的分配与扩展机制(当用完时申请新)同时,我们将使用Mermaid图表展示数据页内部结构表空间层级关系,并给出一个示例的分配过程。注意:用户要求生成相关问题,因此最后需要提出3-5个相关问题。</think>### MySQL 表文件拆分与数据页存储机制详解 MySQL 的 InnoDB 引擎采用**表空间 + 数据页**的二级存储架构实现表文件拆分。核心机制如下: --- #### 、存储层级结构 ```mermaid graph TD A[表空间 Tablespace] --> B[数据页 Page] B --> C[数据行 Row] B --> D[系统信息] ``` 1. **表空间** - 物理对应磁盘文件(如 `ibdata1` 系统表空间或 `表名.ibd` 独立表空间) - 包含多个数据页(默认每个 16KB)[^2][^4] - 类型: - 系统表空间:存储数据字典、undo日志等 - 独立表空间:每表单独文件(推荐) 2. **数据页** - 固定 16KB 大小(可通过 `innodb_page_size` 调整) - 是磁盘 I/O 的最小单位(内存缓存以为单位) - 每个有唯编号(码),通过 B+树索引定位[^4] --- #### 二、数据页内部结构(7部分) ```mermaid graph LR P[数据页] --> F[File Header 38字节] P --> P_H[Page Header 56字节] P --> I_R[Infimum+Supremum 26字节] P --> U_R[User Records 存储行数据] P --> F_S[Free Space 未使用空间] P --> P_D[Page Directory 槽位索引] P --> F_T[File Trailer 8字节] ``` 1. **User Records** - 实际存储行数据的区域 - 采用**行格式**存储(Compact/Redundant/Dynamic) - 插入记录时从 Free Space 划分空间[^4] $$存储过程:\text{Free Space} \xrightarrow{\text{insert}} \text{User Records}$$ 2. **Page Directory** - 槽位索引(slots)实现内快速查找 - 采用二分查找定位记录(类似跳表结构) 3. **行溢出处理** - 当单行数据 > 容量时: ```mermaid graph LR A[主数据页] -->|存储前768字节| B[溢出] A -->|存储溢出地址| C[其他数据页] ``` - Dynamic 行格式仅存储 20 字节指针[^3] --- #### 三、表文件拆分流程 1. **创建表** - 生成 `.frm` 文件(表结构) - 分配表空间文件(`.ibd`) 2. **插入数据** ```python def insert_record(table, row): if 当前空间不足: # Free Space < row_size 分配新数据页(page_id++) # 表空间扩展 初始化新的 File Header else: 从 Free Space 划分空间 写入 User Records 更新 Page Directory 槽位 ``` 3. **扩展示例** | 操作 | 1状态 | 2状态 | |------|--------|--------| | 初始 | Free Space: 16KB | - | | 插入8KB数据 | User Records: 8KB<br>Free Space: 8KB | - | | 再插入10KB数据 | User Records: 16KB | User Records: 2KB<br>Free Space: 14KB | --- #### 四、关键特性 1. **局部性优化** - 相同B+树叶子节点的物理相邻存储 - 预读机制:`innodb_read_ahead_threshold` 2. **空间回收** ```sql ALTER TABLE t ENGINE=InnoDB; -- 重建表释放碎片空间 ``` 3. **类型** | 类型 | 用途 | |------|------| | FIL_PAGE_INDEX | 数据页(B+树节点) | | FIL_PAGE_INODE | 索引节点 | | FIL_PAGE_IBUF_FREE_LIST | Change Buffer | --- #### 五、性能影响 1. **页分裂** - B+树插入导致页分裂(50%填充因子) - 解决方案:设置 `innodb_fill_factor` 2. **碎片率检测** ```sql SHOW TABLE STATUS LIKE '表名'; -- Data_free > 0 表示有碎片 ``` > **实验验证**: > ```sql > CREATE TABLE test (id INT PRIMARY KEY, data BLOB); > INSERT INTO test VALUES (1, RANDOM_BLOB(10000)); -- 插入10KB数据 > SELECT * FROM information_schema.INNODB_TABLESPACES > WHERE NAME LIKE '%test%'; -- 查看分配 > ``` --- ### 结论 MySQL 通过表空间管理物理文件,将数据拆分为 16KB 固定大小的。每采用**七段式结构**管理记录存储,通过 B+树索引实现高效定位。数据页的动态分配机制既能保证存储效率,又能支持大规模数据扩展[^1][^2][^4]。 > 最佳实践:使用独立表空间(`innodb_file_per_table=ON`)+ Dynamic 行格式,定期优化表碎片。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值