mysql数据页是innodb磁盘i/o的最小物理单位,固定16kb,不可绕过直接操作单行;其结构含file header、page header、infimum/supremum、user records、free space、page directory和file trailer,页间通过双向链表连接,支撑b+树组织与范围查询。

MySQL数据页是InnoDB磁盘I/O的最小单位
它不是抽象概念,而是真实存在的16KB物理块——每次从磁盘读一行、查一个索引,InnoDB都必须把整页加载进Buffer Pool。你无法绕过页直接操作单行数据,这是所有性能现象的底层约束。
默认大小由innodb_page_size控制,常见值为16384(16KB),不可运行时修改;少数场景可设为4KB或8KB,但需初始化时指定且不兼容多数备份工具。
- 页内数据按主键顺序物理排列,形成B+树叶子节点的实际载体
- 页之间用双向链表连接(通过
fil_page_prev/fil_page_next字段),支撑范围扫描 - 页不是孤立存在:多个页组成区(Extent,64页=1MB),区再归属段(Segment)和表空间(Tablespace)
一页内部怎么组织真实数据行
页结构不是简单堆叠,而是分层设计,各区域承担明确职责。理解哪些部分可被SQL直接影响,哪些纯属引擎内部管理,能帮你避开误判。
-
Infimum和Supremum是固定虚拟记录,分别代表页内最小/最大边界,不占用户空间,也不计入SHOW TABLE STATUS的行数统计 - 真实数据存在
User Records区,每条记录前有5字节record header,含删除标记、n_owned值、指向下一条记录的指针等 -
Page Directory是页内“索引”,存的是槽(slot)数组,每个slot指向某条记录的起始偏移;查找时先二分定位slot,再线性遍历该slot所属分组 - 空闲空间(
Free Space)从页尾向前增长,新插入记录优先填这里;填满触发页分裂,不是扩容
为什么刚建表就占了114688字节(7个页)
这不是浪费,而是InnoDB的预分配策略:小表起步阶段不直接申请1MB的区(64页),而是用碎片区(fragment extent)分配零散页。7页是MySQL 5.7+的默认初始分配量,可通过information_schema.INNODB_TABLESPACES验证。
- 前32页都来自碎片区,物理上不连续,但逻辑上仍构成B+树结构
- 第33页开始,InnoDB会切换为整区分配(64页连续),提升顺序写入效率
-
FILE_SIZE字段显示的是当前已分配的总字节数,不是实际数据大小;大量DELETE后该值不会自动缩小
数据页对日常开发的真实影响点
很多“奇怪”的现象,追到底都是页行为在起作用。比如自增主键写得快,不是因为ID本身,而是它保证了新行总插入到页尾,避免页内移动和分裂;而UUID主键则频繁引发页分裂和碎片。
- 单页能存多少行?取决于行大小。16KB页减去固定头尾开销(约120字节),再扣除目录槽、记录头等,实际可用约14–15KB。若平均行长200字节,一页约存70–80行
- 更新变长字段(如TEXT、VARCHAR超长)可能使行溢出,溢出部分存入单独的溢出页(
overflow page),主页只留20字节指针 - 执行
OPTIMIZE TABLE本质是重建表,重新组织所有数据页,合并碎片、重排顺序,但会锁表且耗IO
页结构本身不可直接修改,但你能控制它如何被填充:主键设计、行格式(ROW_FORMAT=Dynamic vs Compact)、是否启用页压缩(KEY_BLOCK_SIZE)。这些才是你在SQL层真正能撬动的杠杆。











