InnoDB 磁盘结构
InnoDB的磁盘结构是一个分层、组织精密的体系,核心围绕着表空间(Tablespaces) 展开。它主要由以下几大部分组成:
核心思想:数据存储在表空间文件中!
表空间(Tablespaces)
- 定义: InnoDB存储引擎用于管理存储的逻辑结构,本质上是一个或多个物理磁盘文件(
.ibd)的集合。表空间是数据库数据和元数据的物理容器。 - 主要类型:
- 系统表空间(System Tablespace):
- 文件: 通常是一个名为
ibdata1(也可能有ibdata2等)的文件。 - 存储内容 (在未开启
innodb_file_per_table或特定元数据)- 数据字典(Data Dictionary): 包含关于表结构、列、索引、外键等数据库对象的元数据。
- Change Buffer: 用于加速对非唯一二级索引的插入、删除和更新操作(当目标页不在缓冲池中时)。
- Doublewrite Buffer: 关键机制,用于防止页部分写入(Partial Page Write)。在将页(Page)写入数据文件之前,会先将它们写入这个缓冲区。如果发生崩溃,可以利用这个缓冲区来恢复完整的页。
- Undo Log: (在 MySQL 5.6 之前以及 5.7.1 之后可以配置,默认在系统表空间)** 记录数据修改前的值,用于事务回滚(ROLLBACK)和多版本并发控制(MVCC)。
- 表数据(Table Data): 在 MySQL 5.6.6 之前,或即使开启了
innodb_file_per_table但未完全迁移完的表,数据会存储在系统表空间。 MySQL 5.6.6 引入innodb_file_per_table后,默认新创建的用户表的数据会存储在独立的表空间文件。
- 文件: 通常是一个名为
- 独立表空间/每表文件表空间(File-Per-Table Tablespaces):
- 文件: 每个用户表对应一个独立的
.ibd文件(存储在数据库目录下,如your_database/your_table.ibd)。 - 启用方式: 设置
innodb_file_per_table=ON(MySQL 5.6.6 及以后版本默认开启)。 - 存储内容:
- 该表的数据(Data): 即表中的行记录。
- 该表的索引(Indexes): 包括聚簇索引(主键索引)和所有二级索引。
- 该表的Undo Log: 该表关联的Undo日志段(自 MySQL 8.0 起)。
- 优点:
- 更好的空间管理: 可以单独压缩、备份、恢复、删除单个表空间文件。删除表时可以直接删除.ibd文件回收空间(系统表空间不行)。
- 性能提升: 可以减少碎片,优化 I/O。
- 便于迁移。
- 文件: 每个用户表对应一个独立的
- 通用表空间(General Tablespaces):
- 文件: 用户自定义的
.ibd文件(不在数据库目录下)。 - 创建方式:
CREATE TABLESPACE ... ADD DATAFILE ... - 存储内容: 用户可以指定将多个表存储在其中。
- 用途: 灵活管理存储,可以集中存放多个表,便于管理。支持压缩。
- 文件: 用户自定义的
- Undo 表空间(Undo Tablespaces):
- 文件: 通常命名为
undo_001,undo_002等(在MySQL数据目录或配置的innodb_undo_directory下)。 - 存储内容: 专门存放Undo日志记录。
- 启用: MySQL 5.6 开始引入配置,MySQL 5.7 开始推荐分离,MySQL 8.0 默认至少创建2个初始的Undo表空间并管理其生命周期。
- 目的: 将Undo日志从系统表空间中分离出来,提升管理灵活性和性能。支持在线回收Undo空间(truncate)。
- 文件: 通常命名为
- 临时表空间(Temporary Tablespaces):
- 文件: 默认有
ibtmp1。 - 存储内容: 存放临时表(用户创建的
CREATE TEMPORARY TABLE)和查询执行过程中内部临时表(internal temporary tables)的磁盘数据部分。 - 特点: 重启后会重建(数据丢失)。可以配置大小上限(
innodb_temp_data_file_path)。
- 文件: 默认有
- 系统表空间(System Tablespace):
- 定义: InnoDB存储引擎用于管理存储的逻辑结构,本质上是一个或多个物理磁盘文件(
表空间的内部结构:段、簇、页
每个表空间内部进一步被组织成更小的逻辑单元:- 段(Segment):
- 表空间的主要组织结构单元。
- 每个索引在表空间中占据两个主要的段:
- 叶子节点段(Leaf Segment / B-tree Leaf Node Segment): 存储索引的叶子节点(对于聚簇索引,叶子节点存储的是完整的行数据;对于二级索引,存储的是索引列和主键值)。
- 非叶子节点段(Non-Leaf Segment / B-tree Non-Leaf Node Segment): 存储索引的非叶子节点(即内部节点,用于导航定位到叶子节点)。
- 此外,还存在用于管理回滚段(Undo Segment)的段。回滚段本身包含多个Undo Slot。
- 段由簇(Cluster) 组成。
- 簇(Extent / Cluster):
- 组成: 由连续的页(Page) 组成。
- 大小: 固定为 1MB(在页大小为默认16KB的情况下,一个簇包含
1MB / 16KB = 64个连续的页)。 - 目的: 分配存储空间的基本单位(最初分配给段时,分配一个簇),减少碎片,提高I/O效率(连续存储)。
- 页(Page):
- 定义: InnoDB磁盘管理的最小单位。 所有数据的读写操作,都是以页为单位进行的。数据在写入磁盘之前必须先读入内存中的缓冲池(Buffer Pool)进行操作。
- 大小: 固定 16KB(可以通过编译时参数修改,但非常不推荐,兼容性问题多)。
- 类型: 根据存储内容的不同,页有多种类型:
- 数据页(Index Page / Data Page): 最常见的页类型,用于存储B+树索引的节点(叶子节点和非叶子节点),即实际的行数据和索引项。
- Undo页(Undo Page): 存储Undo日志记录。
- 系统页(System Page): 存储数据字典信息等(主要存在于系统表空间)。
- Insert Buffer Bitmap Page: 管理Change Buffer空间使用情况。
- Insert Buffer Free List Page: 管理Change Buffer的空闲列表。
- FSP_HDR (File Space Header Page): 表空间的第一个页,存储表空间整体元信息,如空间ID、页总数、簇使用情况等。
- INODE Page: 存储段(Segment)的信息(FSP_HDR页包含INODE页的指针)。
- XDES Page (Extent Descriptor Page): 跟踪簇的使用情况(FSP_HDR页包含第一个XDES页的指针)。
- 等等...
- 数据页(Index/Data Page)结构剖析: 这是理解InnoDB行存储的核心。
File Header(38B):记录页的通用信息,如页类型(INDEX)、前一页/后一页指针(构成双链表)、页的校验和(Checksum)、页在表空间中的位置(SPACE_ID & PAGE_NO)等。Page Header(56B):记录页的状态信息,如存储记录数、槽(Slot)数、堆(Heap)信息、垃圾记录链表头指针、上次插入位置、页面层级(在B+树中的深度)等。Infimum + Supremum Records(13B each):系统定义的虚拟最小记录(Infimum)和最大记录(Supremum)。用户记录都逻辑上位于两者之间,便于边界处理。-
User Records(行记录, Row Records): 实际存储行数据的区域。记录按主键顺序紧密存储(对于聚簇索引叶子页)。记录有特定的格式。 -
Free Space: 页中尚未使用的空间。删除记录或插入较小记录后,新记录可能会优先使用这里。 Page Directory(Slot Array):存储页内记录的相对位置(逻辑偏移量),结构是一个稀疏索引。每个槽(Slot)指向页内的一个记录(通常是按主键顺序每组最后几条记录中的一个)。用于页内快速二分查找定位记录。File Trailer(8B):校验点,包含页的校验和。页刷盘后,将此校验和与File Header中的校验和比对,确保页写入完整。
- 段(Segment):
行格式(Row Format)
- 决定了用户记录(User Records) 在数据页内是如何物理存储的。
- 常见格式 (由
ROW_FORMAT决定):-
REDUNDANT(过时): MySQL 5.0.3 之前的默认格式。格式最紧凑但效率相对较低。 -
COMPACT(流行): 比REDUNDANT更高效的存储格式。减少约20%的行空间,特别是对于可变长类型和NULL值。它将变长字段的长度信息集中放在行记录的开头。 -
DYNAMIC(默认): MySQL 5.7.9 (InnoDB 1.2) 及以后版本的默认格式。 是COMPACT格式的增强。主要改进在于处理大对象(BLOB,TEXT,JSON, 大的VARCHAR)。在这些列很大的情况下,DYNAMIC格式只在页中存储一个20字节的指针指向单独分配的"溢出页(Overflow Page)"存储实际的大值。而COMPACT会尝试在行内存储768字节的前缀。这使得DYNAMIC对于包含大对象的表更高效,显著减少了行溢出和碎片。 -
COMPRESSED: 类似于DYNAMIC,但增加了表/页级别的数据压缩功能(使用zlib)。适用于读密集、存储敏感的场景,牺牲一定CPU开销换取空间节省。
-
- 核心优化点:
DYNAMIC格式通过使用溢出页指针,极大地提升了大字段操作的效率和存储空间利用率,是现代应用推荐使用的格式。
索引组织存储
- 聚簇索引(Primary Key / Clustered Index):
- InnoDB表的数据存储方式基于聚簇索引组织。
- 每张表必须且只能有一个聚簇索引(主键索引)。
- 表的数据(行记录)物理上就是按照主键值的顺序存储在叶子节点上的。
- 非叶子节点存储主键值以及指向子节点的指针(页号+槽号)。
- 优点: 按主键检索非常高效(1-3次磁盘I/O通常可定位)。范围查询效率高(连续存储)。
- 缺点: 主键值大小影响所有二级索引的大小和性能(因为二级索引叶子节点存储主键值)。主键修改成本高(需要移动行)。
- 二级索引(Secondary Index / Non-Clustered Index):
- 叶子节点不存储完整的行数据。
- 叶子节点存储的是:
- 索引的列值 (The key columns of the secondary index)
- 对应行的主键值 (The primary key columns of the clustered index)
- 定位完整数据: 如果查询所需列不在二级索引覆盖的列中(即非覆盖索引查询),则需要通过二级索引叶子节点记录的主键值,回到聚簇索引(主键索引)中进行一次“回表”查找(通常通过B+树查找)来获取完整的行数据。这是影响二级索引效率的关键因素!
索引覆盖(Covering Index)可以避免回表。
- 没有显式定义主键怎么办?
- InnoDB会自动检查所有唯一非空索引,选择一个唯一的非空索引(第一个找到的)作为聚簇索引。
- 如果找不到这样的索引,InnoDB会隐式创建一个名为
GEN_CLUST_INDEX的自增ROWID(6字节)作为隐藏的主键(聚簇索引)。隐藏主键会记录在数据字典中,但对用户不可见,也会增加二级索引大小(叶子节点需要存储这个大的ROWID)。
- 聚簇索引(Primary Key / Clustered Index):
其他重要磁盘组件
- 重做日志文件(Redo Log Files):
- 文件: 通常命名为
ib_logfile0和ib_logfile1(默认两个,大小可配)。 - 存储内容: 顺序写入的日志记录,记录了物理层面上对数据页的修改操作(逻辑物理混合)。它是事务持久性的核心保证。
- 工作原理 (Write-Ahead Logging - WAL):
- 事务提交前,必须先将对数据页的所有修改记录写入(持久化到磁盘)Redo Log文件。
- 数据页的修改可能还停留在Buffer Pool中,没有写回磁盘数据文件(.ibd)。
- 如果发生崩溃,重启时通过重放(Replay)这些Redo Log记录,可以将已经提交的事务所做的修改重新应用到数据文件,保证持久性(Durability)。
- 循环写入: Redo Log文件是循环使用的。当写满最后一个文件时,会覆盖写第一个文件(前提是第一个文件中的修改对应的脏页已经被刷盘)。
- 与磁盘结构的关联: Redo Log记录了所有对数据页(最终存储在表空间文件中)的更改。
- 文件: 通常命名为
- Doublewrite Buffer (物理实现):
- 虽然逻辑上属于系统表空间的一部分,但它是一个特殊的磁盘区域。
- 在将脏页写回其真正的表空间数据文件位置之前,InnoDB会先将脏页的一个副本写入Doublewrite Buffer(位于系统表空间中连续的固定位置)。写Doublewrite Buffer是顺序写。
- 之后才会真正将脏页写入其在表空间数据文件(.ibd)中的最终位置(随机写)。
- 目的: 解决部分页写入问题。如果页在写入最终位置的过程中发生崩溃导致页损坏(只写了16KB的一部分),InnoDB在恢复时,可以从Doublewrite Buffer中找到该页的一个完好副本,并用它来覆盖损坏的页。由于Doublewrite Buffer的写是原子性且顺序的,它能保证副本页的完整性。然后可以安全地使用Redo Log重做该页的变化。为页写入失败提供了一道安全网。
- 重做日志文件(Redo Log Files):
图解层次关系 (从大到小):
+---------------------------+
| Database | # 数据库实例,包含多个表空间
+---------------------------+
|
v
+---------------------------+
| Tablespace(s) | # 逻辑容器: ibdata1, table.ibd, undo_001, ibtmp1
+---------------------------+
|
+--------------------------------------------------------+
| |
v v
+-----------------------+ +--------------------------+ +----------------------+
| Segment (e.g., Index | | Segment (e.g., Undo Seg) | | ... Other Segments ...|
| Leaf Segment) | | | | |
+-----------------------+ +--------------------------+ +----------------------+
| |
v v
+----------------------+ +----------------------+
| Extent |----->| Extent | # 由连续的64个页组成 (1MB for 16K Page)
+----------------------+ +----------------------+
|
v
+----------------------+ +----------------------+
| Page (1) |----->| Page (2) | # 16KB 最小单位
+------------+---------+ +------------+---------+
| |
v (Inside Page Structure) v (Inside Page Structure)
+---------------------------------------------------+
| File Header | Page Header | Infimum | User Records |
| (38B) | (56B) | (13B) | (Rows!) |
| ... Free Space ... | Page Directory | File Trailer|
| | (Slots) | (8B) | |
+---------------------------------------------------+
|
v (Inside User Records)
+---------------------------------------------------+
| Row Format (e.g., Dynamic): |
| - Field Length Offsets |
| - Trx ID & Roll Pointer (for MVCC) |
| - Non-NULL Fixed-Length Columns |
| - Non-NULL Variable-Length Columns |
| - NULLable Columns Bitmap |
| - Overflow Page Pointers for large columns |
+---------------------------------------------------+
总结关键点:
表空间为中心: 所有数据最终存储在表空间文件(.ibd, ibdata1, undo_001, ibtmp1)。
页是最小单位: 所有的磁盘I/O(读写、刷盘、缓存)都以16KB的页为单位进行。
索引组织数据: 表数据按主键顺序(聚簇索引)物理存储。二级索引存储索引列+主键值。
页内结构: 数据页有严谨的结构(页头、记录头、行记录、槽目录、页尾),
DYNAMIC行格式优化了大字段存储。段、簇管理: 段(叶子段、非叶子段)是表空间的主要单元,由连续的簇(64个页,1MB)组成,簇再由连续的页组成,利于减少碎片和提高效率。
核心机制:
- 重做日志(Redo Log): 保证事务持久性(先写日志)。
- Doublewrite Buffer: 保证页写入的原子性,防止页部分写入损坏。
- Change Buffer: 加速二级索引的DML操作(在非唯一索引上)。
- Undo Log (在Undo表空间): 支持事务回滚和MVCC。
分离是现代趋势:
- 使用
innodb_file_per_table=ON将用户表数据分离到独立的.ibd文件。 - 使用Undo表空间单独管理Undo日志。
- 临时表空间管理临时数据。
- 使用
理解这些磁盘结构,有助于你更深入地理解InnoDB的运作原理,从而在优化查询(例如设计高效的索引避免回表)、配置存储参数、分析性能瓶颈和进行故障排查时做出更明智的决策。
InnoDB 磁盘结构的更多相关文章
- MySQL之 InnoDB记录结构(转自掘金小册 MySQL是怎样运行的,版权归作者所有!)
以下内容来自掘金小册 MySQL 是怎样运行的:从根儿上理解 MySQL 版权归原作者所有! 页是MySQL中磁盘和内存交互的基本单位,也是MySQL是管理存储空间的基本单位. 指定和修改行格式的语法 ...
- 第五节:从一条记录说起——InnoDB记录结构
<MySQL 是怎样运行的:从根儿上理解 MySQL>第五节:从一条记录说起——InnoDB记录结构 准备工作 现在只知道客户端发送请求并等待服务器返回结果. MySQL什么方式来访 ...
- 详细了解 InnoDB 内存结构及其原理
最近发现,文章太长的话,包含的信息量较大, 并且需要更多的时间去阅读.而大家看文章,应该都是利用的一些碎片时间.所以我得出一个结论,文章太长不太利于大家的吸收和消化.所以我之后会减少文章的长度,2-3 ...
- MySQL之 InnoDB 内存结构
从MySQL 5.5版本开始默认 使用InnoDB作为引擎,它擅长处理事务,具有自动崩溃恢复的特性,在日常开发中使用非常广泛 下面是官方的InnoDB引擎架构图,主要分为内存结构和磁盘结构两大部分. ...
- MySQL-InnoDB磁盘结构
主要阐述InnoDB存储引擎(MySQL5以后的默认引擎). 数据库中最基本的组成结构是数据表,视觉上的表和其对应的磁盘结构如下: 此图参考了厦门大学课堂:MySQL原理 .但是视频中一些更多细节没有 ...
- UBIFS 文件系统分析1 - 磁盘结构【转】
转自:http://blog.csdn.net/kickxxx/article/details/7109662 版权声明:本文为博主原创文章,未经博主允许不得转载. ubifs磁盘结构 UBIFS文件 ...
- [转+整理]LINUX学习笔记(1):磁盘结构及分区
整理自: http://vbird.dic.ksu.edu.tw/linux_basic/0130designlinux_2.php http://lengjianxxxx.blog.163.com/ ...
- linux 磁盘管理三部曲——(1)磁盘结构,认识分区
最近小编整理了磁盘管理的相关知识,发现还是挺多的,所有就分了三个部分来给大家分享一下: 1.磁盘结构,认识分区 2.管理分区,文件系统格式化 3.mount挂载,/etc/fstab配置文件 这篇就先 ...
- [svc][op]磁盘(结构)容量计算
磁盘结构和容量计算 fdisk -l显示信息详解 [root@www.linuxidc.com ~]# fdisk -l Disk /dev/sda: bytes heads, sectors/tra ...
- 使用innodb_ruby探查Innodb索引结构
使用innodb_ruby探查Innodb索引结构 innodb_ruby 是使用 Ruby 编写的 InnoDB 文件格式解析器.innodb_ruby 的目的是暴露一些其他隐藏的 InnoDB 原 ...
随机推荐
- 电梯题目集总结性Blog
一.前言 对这三次题目集的总结: 这三次作业的难度是层层递进的.题目数量安排得当,给的时间也足够用.前面的基础题像搭积木一样,带着我们一步步熟悉怎么设计类和对象:但每次的最后一题就像突然升级的关卡 ...
- WPF 基于Transform实现画布超出边界触发计算
有些场景需要对画布边界做界限控制,此时需要计算画布的四个方向的界限和极值 先看效果图: 画布在通过RenderTransform 做变换,由于在变换的过程中,实际的宽高没有改变,需要通过Transfo ...
- React-Native开发鸿蒙NEXT-图片上传
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
- css样式修改-悬浮数字
代码实现 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- Linux ls 查看目录结构与文档信息
摘要:Linux ls命令用于列出目标目录中所有的子目录和文件,发掘并掌握ls命令及其参数设置可以驾轻就熟地管理文件,随心所欲地浏览并确定所在的位置! ls命令介绍 今天,楼兰胡杨继续跟各位猿友一 ...
- 浅谈Spring、Spring MVC、Spring Boot和Spring Cloud的关系和区别
Spring 框架就像一个家族,有众多衍生产品,例如 boot.security.jpa等等.但它们的基础都是Spring的IOC和AOP等.IOC提供了依赖注入的容器,AOP解决了面向横切面编程 ...
- MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
MyBatis常见面试题:通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗? Dao接口即Mapper接 ...
- 2022 电赛C题 巡线基础模块代码(带控制)
巡线功能模块 from maix import camera, display, gpio, pwm class FindLine(): def __init__(self): self.THRESH ...
- 推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化 ...
- Java常用类Object
1 package com.lv.study.pm; 2 3 public class TestObject { 4 5 public static void main(String[] args) ...