MySQL - 存储引擎之InnoDB磁盘结构
一、InnoDB存储结构
- MySQL官网存储引擎架构图和介绍
https://dev.mysql.com/doc/refman/8.0/en/innodb-architecture.html
根据架构图可以看出,Innodb主要分为内存结构与磁盘结构两部分
二、InnoDB磁盘结构
Tables(表)
(1)表的物理组织:段(Segment)、区(Extent)、页(Page)
InnoDB通过三级结构管理表空间内的存储资源
- 页(Page):16KB的物理存储单元,存储行记录或索引
- 区(Extent):由64个连续页组成(64 × 16KB = 1MB),是分配存储资源的基本单位
- 段(Segment):由多个区组成,是InnoDB为特定对象(如聚簇索引、二级索引)分配的存储逻辑单元,例如:一张表的聚簇索引对应一个段,每个二级索引也对应一个独立的段
举例说明:
一张包含主键和两个二级索引的表,会生成3个段(主键段+两个二级索引段),每个段初始分配1个区(1MB),随着数据增长逐步扩展
(2)表的定义与存储单元
InnoDB的表,是逻辑上的数据集合,其物理存储以页(Page)为最小单位(默认16KB)由变量innodb_page_size控制。
页是InnoDB磁盘I/O的基本操作单元,所有数据(行记录、索引、元数据)均以页的形式存储。
页的内部结构: - 文件头(File Header):描述页的信息,占用38字节
- 页头(Page Header):页的状态信息,占用56字节
- 最大和最小记录(Infimum & Supremum):两个虚拟的行记录,占用26字节
- 用户记录(User Records):存储行记录内容
- 空闲记录(Free Space):页中还没有被使用的空间
- 页目录(Page Directory):存储用户记录的相对位置
- 文件尾(File Trailer):校验页是否完整,占用8字节
Indexes(索引)
聚簇索引
聚簇索引是InnoDB表的核心索引,其B+树结构直接存储数据行,因此一张表只能有一个聚簇索引
(1)结构特点
- B+树层级:根节点 -> 中间节点 -> 叶子节点,根节点存储索引键的范围,中间节点用于快速定位,叶子节点存储完整数据行
- 主键强制:聚簇索引的键必须是主键(若未显示定义主键,InnoDB会自动生成隐藏的6字节ROW_ID作为聚簇索引键)
- 数据顺序:数据行按主键顺序物理存储(逻辑上有序,物理上可能因页分裂调整)
(2)性能影响 - 主键选择直接影响查询效率:短主键(如INT)可减少B+树层级(通常3-4层即可覆盖亿级数据),长主键(UUID)会导致页分裂频繁、索引碎片
- 范围查询(如WHERE id BETWEEN 100 AND 2O0)可利用B+树的顺序特性,通过“索引扫描”高效完成
非聚簇索引
非聚簇索引(如普通索引、唯一索引)是独立于聚簇索引的B+树结构,其叶子节点不存储数据行,而是存储聚簇索引键的值
(1)结构特点 - B+树结构:与非聚簇索引的键(如name字段)关联,叶子节点存储主键值
- 回表查询:通过非聚簇索引找到主键后,需再次通过聚簇索引查询完整数据行(称为“回表”)
- 覆盖索引:若查询仅需非聚簇索引的键值(如SELECT id,name FROM t_user WHERE name = '张三'),则无需回表,直接通过非聚簇索引返回结果(性能最优)
(2)设计原则 - 高频查询字段有限:为WHERE、JOIN、ORDER BY中频繁使用的字段建索引
- 复合索引顺序:遵循“最左匹配原则”(如索引(a,b,c)可优化WHERE a=1、WHERE a=1 AND b=2,但无法优化WHERE b=2)
- 避免冗余索引:如已有(a,b),无需再建(a)(前者已覆盖后者)
Tablespaces(表空间)
系统表空间(System Tablespaces)
系统表空间是更改缓冲区的存储区域,如果表是在系统表空间而不是每个表文件或通用表空间中创建的,它也可能包含表和索引数据
在MySQL5.x版本当中,还会包含InnoDB数据字典以及Undolog。
涉及参数:innodb_data_file_path
每张表独立表空间(File-Per-Table Tablespaces)
每个表的文件表空间包含单个InnoDB表的数据和索引,并存储在文件系统上的单个数据文件中
独立表空间参数默认开始 ON,不会去放在系统表空间
涉及参数:innodb_file_per_table
通用表空间(General Tablespaces)
通用表空间,需要通过CREATE TABLESPACE语法创建通用表空间,在创建表时,可以指定该表空间
创建语法:CREATE TABLESPACE xxx ADD DATAFILE '${file_name}' ENGINE = ${engine_name};
示例:
撤销表空间(Undo Tablespaces)
撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undo log日志
临时表空间(Temporary Tablespaces)
InnoDB使用会话临时表空间和全局临时表空间,存储用户创建的临时表等数据
双写缓冲区(Doublewrite Buffer Files)
双写缓冲区,InnoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双写缓冲区文件中,便于系统异常时恢复数据
重做日志(Redo Log)
重做日志,用来实现事务的持久性,该日志文件由两部分组成:
- 重做日志缓冲(redo log buffer):在内存中
- 重做日志文件(redo log):在磁盘中
当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘时,发生错误时,进行数据恢复使用