MySQL索引B+树?主键索引每一个节点的大小?一个 page 多大?如果一条数据大于 16KB 怎么存?text 最多存多少数据?行溢出怎么办?数据存储格式有哪些?溢出页如何管理?

MySQL 索引与 B+ 树

1. B+ 树结构
  • 索引实现:InnoDB 使用 B+ 树作为索引结构,所有数据存储在叶子节点,非叶子节点仅存储键值和子节点指针。
  • 聚簇索引(主键索引):叶子节点存储完整的行数据。
  • 二级索引:叶子节点存储主键值,通过回表查询获取完整数据。

2. 页(Page)大小

  • 默认页大小:InnoDB 的默认页大小为 16KB(通过 innodb_page_size 可配置,但通常不建议修改)。
  • 每个节点对应一个页:B+ 树的每个节点(非叶子/叶子节点)对应一个页,因此主键索引的每个节点大小也是 16KB。

3. 大字段存储与行溢出

(1) 行溢出(Row Overflow)
  • 触发条件:当一行数据的总大小超过页大小(16KB)时,InnoDB 会将部分数据存储到 溢出页(Overflow Page)
  • 存储策略
    • 行内存储前缀:对于 VARCHARTEXTBLOB 等可变长字段,InnoDB 会优先在行内存储前 768 字节,剩余内容存到溢出页。
    • 溢出页指针:行内存储 20 字节的指针(指向溢出页地址和长度)。
(2) TEXT 类型的最大存储
  • 理论最大值:单个 TEXT 字段最多存储 4GB 数据(实际受行格式和 MySQL 版本限制)。
  • 实际限制:需通过多个溢出页分段存储。

4. 数据存储格式(Row Format)

InnoDB 支持多种行格式,直接影响大字段存储和溢出机制:

行格式 特点
Compact - 默认格式(MySQL 5.6 之前)。
- 行内存储字段长度信息,较紧凑。
- 大字段前 768 字节存行内,其余存溢出页。
Redundant - 旧格式,兼容性高但存储效率低。
Dynamic - MySQL 5.7+ 默认格式。
- 对大字段优化:仅存储 20 字节指针,全部内容存溢出页,减少行内空间占用。
Compressed - 在 Dynamic 基础上支持数据压缩(通过 KEY_BLOCK_SIZE 配置)。

5. 溢出页管理

  • 分配机制:当行数据超过页容量时,InnoDB 自动分配溢出页,并通过指针链接。
  • 存储结构
    • 每个溢出页可存储多个行的溢出数据片段。
    • 溢出页本身通过链表或 B+ 树结构管理(取决于数据量)。
  • 查询过程:访问大字段时,先读取行内指针,再根据指针定位溢出页数据。

6. 关键问题总结

问题 答案
主键索引节点大小 每个节点对应一个页,默认 16KB。
页大小 默认 16KB,由 innodb_page_size 控制。
一条数据超过 16KB 存储 行溢出机制:行内存储前缀 + 溢出页指针,剩余内容存溢出页。
TEXT 最大存储 理论 4GB(实际受行格式限制,Dynamic 格式更高效)。
行溢出问题 通过溢出页和指针管理,避免单页容量不足。
数据存储格式 Compact(旧)、Dynamic(推荐)、Compressed(压缩),不同格式对大字段处理策略不同。
溢出页管理 自动分配,行内存储指针,溢出页通过链表或 B+ 树组织。

7. 示例与场景

场景:存储大文本数据(TEXT 类型)
  1. 行格式为 Dynamic
    • 行内仅存储 20 字节指针,所有文本内容存入溢出页。
    • 查询时根据指针定位溢出页,分片读取数据。
  2. 行格式为 Compact
    • 行内存储前 768 字节,剩余内容存入溢出页。
    • 可能导致行内空间浪费(若字段内容频繁更新)。

8. 优化建议

  • 合理选择行格式:优先使用 Dynamic 格式以优化大字段存储。
  • 避免超长行:拆分大字段到独立表,通过主键关联。
  • 监控溢出页:通过 INFORMATION_SCHEMA.INNODB_TABLES 查看表溢出页数量,评估存储效率。

你可能感兴趣的:(mysql,b树,数据库)