一篇文章告诉你MySQL 一行记录是怎么存储的?
前言你是否思考过以下问题MySQL 的 NULL 值会占用空间吗MySQL 怎么知道 varchar(n) 实际占用数据的大小varchar(n) 中 n 最大取值为多少行溢出后MySQL 是怎么处理的这些问题看似毫不相干其实都在围绕「MySQL 一行记录的存储结构」这一个知识点。本文就来深入探讨 MySQL 一行记录的存储方式。一、MySQL 的数据存放在哪个文件MySQL 数据默认存放在以下目录进入对应数据库目录可看到三个文件db.opt存储当前数据库的默认字符集和字符校验规则t_order.frm保存表结构定义元数据t_order.ibd保存表数据独占表空间文件从 MySQL 5.6.6 版本开始innodb_file_per_table参数默认为 1每张表的数据都存放在独立的.ibd文件中。二、表空间文件的结构表空间由段segment、区extent、页page、行row组成结构说明行row数据库表中的记录按行存放页pageInnoDB 读写的最小单位默认 16KB区extent由 64 个连续页组成大小为 1MB解决随机 I/O 问题段segment包括索引段、数据段、回滚段三、InnoDB 行格式有哪些InnoDB 提供了 4 种行格式行格式特点Redundant古老格式MySQL 5.0 之前使用Compact紧凑格式MySQL 5.1 默认DynamicMySQL 5.7 起默认基于 Compact 改进Compressed类似 Dynamic支持压缩本文重点介绍Compact行格式。四、COMPACT 行格式详解Compact 行格式分为记录的额外信息和记录的真实数据两部分text---------------------------------------------------------- | 记录的额外信息 | 记录的真实数据 | ---------------------------------------------------------- | 变长字段长度列表 | NULL值列表 | 记录头信息 | 隐藏列 | 真实列 | ----------------------------------------------------------1. 变长字段长度列表存储变长字段varchar、text、blob 等实际占用的字节数按列的顺序逆序存放每个变长字段的长度用 1 或 2 字节表示最大字节数 ≤ 255 → 1 字节最大字节数 255 → 2 字节为什么逆序存放为了提高 CPU Cache 命中率使得位置靠前的记录的真实数据和对应的长度信息可同时在一个 Cache Line 中。注意当数据表没有变长字段时没有此列表。2. NULL 值列表存储值为 NULL 的列标记每个允许为 NULL 的列对应 1 个二进制位按列顺序逆序排列位值为 1 表示 NULL0 表示非 NULL必须用整数个字节表示不足高位补 0示例年龄字段为 NULL 的记录NULL 值列表十六进制表示为0x04。注意当所有字段都定义为 NOT NULL 时没有此列表可节省 1 字节空间。3. 记录头信息字段说明delete_mask标识是否被删除标记删除非真正删除next_record下一条记录的位置链表组织record_type记录类型0普通1非叶子节点2最小记录3最大记录4. 记录的真实数据包含三部分用户定义的列隐藏列row_id6 字节无主键/唯一约束时存在trx_id6 字节事务 ID必需roll_pointer7 字节版本指针必需五、varchar(n) 中 n 最大取值为多少关键前提MySQL 规定除 TEXT、BLOB 外一行记录所有列占用的字节长度不含隐藏列和记录头不能超过 65535 字节。单字段情况字符集 ascii假设只有varchar(n)一个字段且允许 NULL65535 - 变长字段长度列表(2) - NULL值列表(1) 65532所以n 最大为 65532。不同字符集下的计算字符集每字符最大字节数varchar(n) 最大 nascii165532UTF-832184465532/3多字段情况所有字段长度 变长字段长度列表 NULL 值列表 ≤ 65535六、行溢出后MySQL 怎么处理一个数据页默认 16KB16384 字节当一行记录超过此大小时发生行溢出。Compact 行格式处理方式记录的真实数据处保存该列的一部分数据剩余数据放入溢出页原处用20 字节存储指向溢出页的地址Dynamic / Compressed 行格式处理方式记录的真实数据处不存储实际数据只存储20 字节指针指向溢出页实际数据全部存储在溢出页中七、总结问题答案NULL 值如何存放存储在「NULL 值列表」中不占用真实数据空间如何知道 varchar 实际长度通过「变长字段长度列表」存储varchar(n) 最大 n 是多少需减去长度列表和 NULL 列表占用的空间如单字段 ascii 下最大 65532行溢出如何处理溢出数据存到「溢出页」原记录保存指针