2026/1/16 17:39:56
网站建设
项目流程
做网页游戏网站需要什么,晋中做网站的公司,郑州网站建设xinsu360,东莞网站设计怎么做?引言为什么要理解“一行记录是如何存储的”#xff1f;在使用 MySQL 时#xff0c;我们经常会遇到这些问题#xff1a;为什么 VARCHAR 过长会影响性能#xff1f;NULL 字段真的“不占空间”吗#xff1f;为什么 InnoDB 推荐 使用自增主键#xff1f;行溢出#xff08;ro…引言为什么要理解“一行记录是如何存储的”在使用 MySQL 时我们经常会遇到这些问题为什么VARCHAR 过长会影响性能NULL 字段真的“不占空间”吗为什么 InnoDB 推荐使用自增主键行溢出row overflow是怎么发生的BTree 中一行记录到底长什么样这些问题的答案都指向同一个核心MySQL 是如何在磁盘中存储一行数据的要真正理解这些问题我们必须从文件结构 → 表空间 → 页 → 行格式逐层拆解。一、MySQL 的数据到底存放在哪些文件里假设我们有一张表CREATE TABLE t_order ( id BIGINT PRIMARY KEY, user_id BIGINT, amount INT, remark VARCHAR(255) ) ENGINEInnoDB;在磁盘上MySQL 至少会涉及以下文件。2.1 db.opt —— 数据库级别配置文件作用保存数据库默认字符集、排序规则示例内容default-character-setutf8mb4 default-collationutf8mb4_general_ci2.2 t_order.frm —— 表结构定义文件MySQL 8.0 前保存表的结构信息包括字段名、字段类型、索引定义等MySQL 8.0 之后表结构元数据被统一存储到数据字典表中.frm文件逐步退出历史舞台2.3 t_order.ibd —— InnoDB 独立表空间文件重点真正存放数据 索引的地方是t_order.ibd是否生成这个文件取决于一个核心参数。2.4 innodb_file_per_table 参数innodb_file_per_table ON参数值行为ON默认每张表一个.ibd文件OFF所有表共享系统表空间ibdata1生产环境强烈建议 ON原因表可独立回收空间避免 ibdata1 无限膨胀便于迁移与维护二、InnoDB 表空间的物理结构.ibd文件并不是“一坨连续数据”而是有明确层级结构表空间Tablespace └── 段Segment └── 区Extent └── 页Page └── 行Row我们逐层拆解。三、页Page—— InnoDB 的最小存储与 IO 单位4.1 页的基本概念默认大小16KBInnoDB 所有读写都是以页为单位没有“只读一行”这回事至少读一页。4.2 页的类型页类型说明数据页存放行记录索引页BTree 节点Undo 页Undo Log系统页数据字典本文重点关注数据页Index Page。4.3 数据页内部结构简化Page Header Page Directory Infimum Record User Records真实行数据 Supremum Record其中User Records 就是行真正存储的位置。四、段Segment与区Extent5.1 区Extent一个区 64 个连续页默认大小64 × 16KB 1MB作用减少磁盘随机 IO5.2 段SegmentInnoDB 中常见段类型数据段Leaf Segment索引段Non-leaf Segment回滚段Rollback Segment一个 BTree 至少包含两个段五、InnoDB 支持的行格式Row Format6.1 行格式类型行格式说明REDUNDANT老格式已淘汰COMPACT经典格式重点DYNAMIC大字段更友好COMPRESSED压缩存储MySQL 5.7 / 8.0 默认使用 COMPACT / DYNAMIC六、COMPACT 行格式详解重点一条 InnoDB 行在 COMPACT 格式下逻辑结构如下变长字段长度列表 NULL 值列表 记录头信息 真实数据七、为什么大字段7.1 记录的额外信息① 变长字段长度列表逆序存放仅包含VARCHAR / VARBINARY / TEXT 等变长字段按字段定义顺序的逆序存储为什么要逆序因为读取记录时从后向前解析字段更高效避免解析时频繁移动指针有利于 CPU cache 友好访问② NULL 值列表每个可为 NULL 的字段占 1 bit按字段顺序排列如果字段都 NOT NULL则不存在该列表结论NULL 并不是“不占空间”只是占得很少7.2 记录头信息5 字节包含大量重要元信息字段作用delete_mask是否被删除min_rec_mask最小记录标记n_owned分组信息heap_no堆中位置record_type记录类型next_record指向下一条记录链表结构页内行记录是“单向链表”7.3 记录的真实数据存放定长字段INT、BIGINT变长字段的真实内容或溢出指针7.4 隐藏字段非常重要InnoDB 会为每行记录自动添加 3 个隐藏字段字段大小作用DB_ROW_ID6 字节无主键时生成DB_TRX_ID6 字节最近一次修改事务DB_ROLL_PTR7 字节指向 Undo LogMVCC、事务回滚、可见性判断的核心基础可能不直接存储在行内当一行记录过大时InnoDB 会将部分字段存入溢出页Overflow Page行内只保留20 字节左右的指针不同格式策略行格式大字段策略COMPACT尽量行内DYNAMIC更早溢出COMPRESSED压缩后再存总结一行记录的完整存储链路SQL 插入↓InnoDB 表空间.ibd↓段Segment↓区Extent↓页Page16KB↓COMPACT 行结构├─ 变长字段长度列表├─ NULL 值列表├─ 记录头信息├─ 隐藏字段└─ 真实数据