InnoDB .ibd文件存储疑问:整数存储与溢出页解析
MySQL InnoDB(Dynamic行格式)存储格式疑问解答
测试环境与表信息
MySQL版本:8.0.32
行格式:Dynamic
测试表结构及数据:
CREATE TABLE `demo` ( `id` int NOT NULL, `age` int NOT NULL, `name` varchar(20000) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=ascii; INSERT INTO demo(id, age, name) VALUES (1, 10, 'joker'), (2, 11, 'tom'), (3, 12, 'jerry'), (4, 12, 'aaaa...20000 in total...a'), (5, 16, NULL);
疑问解答
1. 为何MySQL存储有符号整数时未采用补码形式?
InnoDB存储有符号整数时,采用的是偏移量编码而非补码:将有符号整数的取值范围整体偏移,把负数转换为无符号数存储。以int类型为例,其原生取值范围是-231到231-1,存储时会给每个值加上231,原最小值-231会变成0,最大值231-1变成232-1,最终以无符号整数的形式存储。
这种设计的核心是适配B+树的有序性需求,偏移后的无符号数直接按二进制比较大小,结果和逻辑值的排序完全一致,无需额外处理补码符号位的排序逻辑,能简化索引的比较与排序操作,提升整体效率。
2. 当行中所有变长字段均为NULL时,是否不额外存储长度字节?
是的。在Dynamic行格式下:
- 行记录的NULL标志位(NULL bitmap)会标记哪些字段为NULL;
- 只有当存在至少一个非NULL的变长字段时,才会在行头部分存储变长字段长度列表(每个非NULL变长字段对应1或2个字节的长度值,根据实际长度大小选择);
- 如果所有变长字段都为NULL,不会额外存储长度字节,因为没有需要记录长度的非NULL变长字段。
比如测试数据中的第5行(id=5, age=16, name=NULL),无任何非NULL的变长字段,因此行记录中不会有变长长度字节的存储开销。
3. 变长字段过长导致页溢出时,额外字节代表什么含义?
在Dynamic行格式下,当变长字段的长度超过页大小的1/4(默认页大小为16KB,即超过4KB)时,会触发页溢出:
- 原行记录中仅存储该字段的20字节指针,这个指针指向实际存储字段内容的溢出页(或溢出段);
- 这20字节的结构为:
表空间ID(4字节) + 溢出页号(4字节) + 页内偏移量(4字节) + 字段总长度(8字节),通过这套指针可以准确定位到溢出内容的位置。
和Compact行格式不同,Dynamic格式不会在原行中存储字段的前缀内容,仅存储完整指针,以此最大程度节省原数据页的空间,提升页内存储密度。
内容的提问来源于stack exchange,提问作者spin
相关产品推荐
相关产品推荐

