MySQL中B+树节点是如何序列化存储到磁盘文件的?
B+树节点在MySQL磁盘文件中的序列化与存储逻辑
以最常用的InnoDB引擎为例,它对B+树的磁盘存储有一套成熟的实现规则:
基础存储单元:页
InnoDB不管是共享表空间ibdata1,还是开启innodb_file_per_table参数后每个表对应的独立.ibd文件,全部按照固定大小的页来管理存储空间,默认页大小为16KB,B+树的每个节点就对应一个物理页。
节点序列化规则
每个页的内容按照固定结构序列化写入磁盘,整体分为头部元数据、存储内容区、尾部校验和三部分:
- 页头部占固定38字节,存储元信息:包括当前页号、页类型(区分是B+树非叶子节点、叶子节点、undo页还是系统页等)、同层相邻的上一个/下一个页号(对应B+树叶子节点的双向链表逻辑)、当前页已存储的记录数、页的空闲空间偏移等。所有元字段都按照固定字节长度、统一字节序写入,读取的时候直接按偏移量解析即可。
- 非叶子节点内容区按顺序存储索引条目:每个条目结构为「索引键值 + 子节点页号」,条目长度根据索引字段类型计算,变长字段会额外存储长度标识。
- 聚簇索引叶子节点内容区存储完整的行数据:每条记录包括行头、隐藏字段(事务ID、回滚指针、主键)、用户定义的列值,变长列会在记录头部存储长度偏移列表。
- 二级索引叶子节点内容区存储的条目为「索引键值 + 对应聚簇索引主键值」。
单文件寻址逻辑
所有页在表空间文件中的位置由页号直接映射:默认配置下,页号为N的页,在单文件中的起始偏移量为N * 16KB,数据库可以直接通过这个偏移量调用pread/pwrite类系统调用定位到对应位置读写,不需要遍历整个文件,因此所有B+树节点可以整齐排列在同一个磁盘文件中。
关于随机访问的问题
你判断的没错,原生B+树的读写逻辑确实不可避免随机访问,但InnoDB做了大量优化来降低随机IO的开销:
- 首先是Buffer Pool内存缓存:热点页会长期驻留内存,读写操作优先命中缓存,不需要每次都访问磁盘。
- 写入操作通过WAL机制优化:更新操作先写顺序写入的redo log记录变更,再异步将内存中的脏页批量刷回磁盘,把大量随机写转化为顺序写,降低延迟。
- 非唯一二级索引的插入/更新操作通过Change Buffer优化:不需要立刻读取对应的索引叶子节点到内存,先将变更记录在Change Buffer中,后台异步批量合并到磁盘节点,减少随机读次数。
- 预读机制:顺序查询时会提前加载相邻的页到缓存,大范围扫描时几乎不需要额外随机读。
内容的提问来源于stack exchange,提问作者mrpre
相关产品推荐
相关产品推荐

