《深入理解 MySQL InnoDB:表空间、Page、Redo Log、Undo、Binlog 与慢查询日志一次讲清楚》
2026/9/1 5:30:15 网站建设 项目流程

深入理解 MySQL InnoDB:从表空间、页到 Redo Log、Binlog 和慢查询日志

  • 深入理解 MySQL InnoDB:从表空间、页到 Redo Log、Binlog 和慢查询日志
    • 前言
  • 一、InnoDB 的整体存储结构
  • 二、InnoDB 逻辑存储结构
    • 1. Tablespace:表空间
  • 三、Segment:段
  • 四、Extent:区
  • 五、Page:InnoDB 最重要的存储单位
    • 1. 为什么 Page 很重要?
    • 2. 常见 Page 类型
  • 六、Row:最终的数据记录
  • 七、InnoDB 的物理文件
  • 八、数据文件:ibdata 与 .ibd
  • 九、Redo Log:保证事务持久性的关键日志
    • 1. 为什么需要 Redo Log?
  • 十、Redo Log 和 Binlog 到底有什么区别?
  • 十一、Undo:保存数据修改前的信息
    • 1. 事务回滚
    • 2. MVCC
  • 十二、MySQL 配置文件
  • 十三、常见 MySQL 配置参数
    • 动态参数与静态参数
  • 十四、Error Log:排查 MySQL 故障的第一现场
  • 十五、Binlog:MySQL 数据恢复和复制的核心日志
  • 十六、Binlog 有什么作用?
    • 1. 主从复制
    • 2. 数据恢复
  • 十七、Binlog 的三种格式
    • 1. STATEMENT
    • 2. ROW
    • 3. MIXED
  • 十八、如何查看 Binlog 是否开启?
  • 十九、Slow Query Log:定位慢 SQL 的重要工具
    • 1. 临时开启慢查询日志
    • 2. 如何验证慢查询日志?
  • 二十、mysqldumpslow:快速分析慢日志
  • 二十一、General Log:记录几乎所有数据库操作
  • 二十二、Relay Log:主从复制中的中继日志
  • 二十三、PID 文件
  • 二十四、Socket 文件
  • 二十五、表结构元数据发生了什么变化?
  • 二十六、MySQL 8.0 学习时一定要注意“版本问题”
  • 二十七、把所有核心日志放在一起理解
  • 二十八、InnoDB 存储体系全景图
  • 总结

深入理解 MySQL InnoDB:从表空间、页到 Redo Log、Binlog 和慢查询日志

前言

InnoDB 是 MySQL 最常用、也是默认的事务型存储引擎。

平时写 SQL 时,我们看到的通常只是数据库、表、字段和索引,例如:

CREATETABLEuser(idBIGINTPRIMARYKEY,nameVARCHAR(50));

但一条数据真正落到磁盘后,并不是简单地“保存到一个表文件里”。

在 InnoDB 内部,数据会经过一套完整的存储体系:

表空间 ↓ 段 ↓ 区 ↓ 页 ↓ 行

与此同时,MySQL 还会维护多种文件与日志:

.ibd 数据文件 redo log undo log binlog error log slow query log general log relay log PID 文件 Socket 文件

这些组件共同完成数据存储、事务恢复、主从复制、故障排查以及 SQL 性能分析。

本文就从底层存储结构开始,系统梳理 InnoDB 的核心组成。


一、InnoDB 的整体存储结构

InnoDB 的存储结构可以分成两个角度理解:

InnoDB ├── 逻辑存储结构 │ ├── Tablespace │ ├── Segment │ ├── Extent │ ├── Page │ └── Row │ └── 物理存储结构 ├── 数据文件 ├── Redo Log ├── Undo ├── 配置文件 ├── 各类运行日志 └── 其他辅助文件

逻辑存储结构描述的是:

InnoDB 如何组织和管理数据。

物理存储结构描述的则是:

这些数据最终以什么文件形式存在磁盘上。

理解 InnoDB,最好先从逻辑层开始。


二、InnoDB 逻辑存储结构

1. Tablespace:表空间

表空间可以理解为 InnoDB 逻辑存储结构中的最高层。

InnoDB 的各种数据最终都存储在不同类型的表空间中。

早期 InnoDB 经常使用共享系统表空间,例如:

ibdata1

可以在 MySQL 数据目录中看到类似文件:

ls-lh/usr/local/mysql/data/

如果使用独立表空间,则每张 InnoDB 表通常拥有自己的.ibd文件。

与之相关的重要参数是:

SHOWVARIABLESLIKE'innodb_file_per_table';

常见结果:

innodb_file_per_table ON

开启独立表空间之后,一张表的数据和索引可以保存在自己的.ibd文件中。

例如:

demo/ ├── user.ibd ├── orders.ibd └── product.ibd

不过要注意:

独立表空间并不意味着 InnoDB 的所有数据都会进入.ibd文件。

例如系统级信息、Undo、部分内部结构等可能存储在其他专用表空间或系统区域中。


三、Segment:段

表空间内部继续划分为 Segment,也就是“段”。

典型的 Segment 包括:

数据段 索引段 回滚段

对于 InnoDB 来说尤其值得注意的一点是:

InnoDB 是索引组织表(Index Organized Table)。

也就是说,InnoDB 表中的数据本身就是按照索引结构组织的。

对于聚簇索引而言:

索引 ≈ 数据组织结构

因此,不能完全把“索引文件”和“数据文件”理解成两套互不相关的东西。

InnoDB 的主键索引叶子节点本身就保存了完整的行数据。


四、Extent:区

Segment 继续向下划分,就是 Extent,也就是“区”。

Extent 是由一组连续的 Page 组成的空间分配单位。

在默认 16KB Page 的情况下,一个 Extent 通常包含:

64 个 Page

因此:

64 × 16KB = 1024KB = 1MB

也就是说,在典型配置下:

1 Extent = 1MB

可以理解为:

Tablespace ↓ Segment ↓ Extent(约 1MB) ↓ Page

为什么不直接一页一页申请空间?

因为如果数据库频繁向操作系统申请极小的存储空间,会增加管理成本。

采用 Extent,可以一次申请一组连续页面,有利于提高空间管理和顺序访问效率。


五、Page:InnoDB 最重要的存储单位

如果只记住一个概念,那么一定要记住:

Page 是 InnoDB 最基本、最核心的磁盘存储单位。

默认情况下,InnoDB Page 大小通常为:

16KB

可以查看:

SHOWVARIABLESLIKE'innodb_page_size';

典型结果:

innodb_page_size 16384

16384 Byte 正好是:

16KB

1. 为什么 Page 很重要?

当 MySQL 查询一条记录时,并不是只从磁盘读取那几十个字节的数据。

磁盘和内存之间的数据交换通常是以 Page 为基本单位进行的。

简单理解:

磁盘 ↓ 16KB Page ↓ Buffer Pool ↓ SQL 使用数据

所以在分析 MySQL:

  • 索引
  • Buffer Pool
  • 随机 IO
  • 顺序 IO
  • 页分裂
  • 页命中率

这些问题时,Page 都是基础概念。


2. 常见 Page 类型

InnoDB 中并不是所有 Page 都用来存放普通数据。

常见页面包括:

数据页 Undo 页 系统页 事务系统页 插入缓冲相关页面 大对象页面 压缩大对象页面

其中实际开发中最常接触的是:

B+Tree 数据页

InnoDB 索引树中的节点就是由一个个 Page 构成的。


六、Row:最终的数据记录

Page 再往下,就是 Row,也就是行。

InnoDB 是一个:

Row-Oriented Storage Engine

即面向行的存储引擎。

例如:

INSERTINTOuserVALUES(1,'Tom',18);

最终数据会以行记录的形式存放在数据页中。

从宏观到微观,可以形成完整关系:

Tablespace ↓ Segment ↓ Extent ↓ Page ↓ Row

这条关系是理解 InnoDB 存储结构的核心。


七、InnoDB 的物理文件

理解完逻辑结构,再来看数据真正落到操作系统后,会出现哪些文件。


八、数据文件:ibdata 与 .ibd

InnoDB 最直接的数据文件主要可以分为:

系统表空间文件 独立表空间文件

传统的系统表空间文件常见:

ibdata1

独立表空间文件则通常是:

表名.ibd

例如:

demo/ ├── user.ibd ├── orders.ibd └── goods.ibd

在开启:

innodb_file_per_table

之后,每张 InnoDB 表通常会建立自己的独立表空间文件。

这使得单表空间管理更加灵活。


九、Redo Log:保证事务持久性的关键日志

Redo Log 是理解 InnoDB 必须掌握的日志。

它属于:

InnoDB 存储引擎层

核心目标是:

保证数据库发生异常宕机之后,已经提交或需要恢复的修改能够重新恢复出来。


1. 为什么需要 Redo Log?

假设执行:

UPDATEaccountSETmoney=money-100WHEREid=1;

如果每次事务提交都必须立刻把所有修改过的数据页随机写入磁盘,那么性能会非常差。

因为数据页可能分布在磁盘不同位置。

InnoDB 会利用 Redo Log,将随机的数据页修改转变为更适合持久化的日志写入。

可以简单理解成:

修改数据 ↓ Buffer Pool 中的 Page 被修改 ↓ 产生 Redo ↓ Redo 持久化 ↓ 脏页之后再刷入数据文件

如果数据库突然宕机:

数据文件可能还没完全写入

但只要 Redo 中记录了必要的修改信息,就可以在数据库重新启动时进行恢复。


十、Redo Log 和 Binlog 到底有什么区别?

这是 MySQL 面试中非常高频的问题。

虽然两者都叫“日志”,但完全不是一回事。

可以从几个维度理解。

对比项Redo LogBinlog
所属层次InnoDB 存储引擎层MySQL Server 层
主要用途崩溃恢复复制、数据恢复
内容特点偏物理变化逻辑事件/行变化
写入方式持续写入按事务记录
使用方式循环使用的日志空间机制持续生成新的日志文件
典型场景Crash Recovery主从复制、时间点恢复

可以用一句话记忆:

Redo Log:保证数据库自己“摔倒还能爬起来” Binlog:记录数据库“做过什么”

十一、Undo:保存数据修改前的信息

与 Redo 对应的另一个重要概念就是 Undo。

Redo 更关注:

如何把修改重新做一遍

Undo 则更关注:

如何获得修改前的数据版本

当一条记录发生修改时,InnoDB 会产生相应的 Undo 信息。

Undo 在两个场景中非常重要:

事务回滚 MVCC

1. 事务回滚

例如:

BEGIN;UPDATEaccountSETmoney=0WHEREid=1;ROLLBACK;

执行ROLLBACK后需要将数据恢复到修改之前的状态。

这时就需要借助 Undo 信息。


2. MVCC

当一个事务修改某条记录时,另一个事务可能仍然需要读取它之前的版本。

这就是:

Multi-Version Concurrency Control MVCC

InnoDB 可以借助 Undo 中保存的历史版本构造一致性读需要的数据。

因此:

Redo → 重做 Undo → 撤销 / 历史版本

两者的作用完全不同。


十二、MySQL 配置文件

MySQL 启动时需要读取配置文件。

在 Linux 环境下,常见配置文件位置可能包括:

/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf

可以使用:

mysql--help|grepmy.cnf

查看配置文件搜索路径。

如果需要明确指定某个配置文件,可以在启动时使用相应参数,例如:

mysqld --defaults-file=/etc/my3306.cnf

十三、常见 MySQL 配置参数

MySQL 配置通常分为服务端和客户端。

例如服务端:

[mysqld] port=3306 basedir=/usr/local/mysql datadir=/usr/local/mysql/data

客户端:

[client] port=3306 default-character-set=utf8mb4

常见参数包括:

port basedir datadir socket pid-file character-set-server lower_case_table_names default-storage-engine log-error

动态参数与静态参数

MySQL 参数还可以从是否支持在线修改的角度分类。

一部分参数可以动态修改,例如:

SETGLOBAL参数名=;

或者:

SETSESSION参数名=;

两者区别是:

GLOBAL ↓ 影响之后建立的连接或全局环境 SESSION ↓ 只影响当前连接

而部分静态参数通常需要:

修改配置文件 + 重启 MySQL

才能生效。


十四、Error Log:排查 MySQL 故障的第一现场

Error Log,即错误日志。

它会记录 MySQL:

启动 运行 异常 关闭 故障

等过程中产生的重要信息。

可以查看相关配置:

SHOWVARIABLESLIKE'log_error';

当出现:

MySQL 启动失败 表空间文件丢失 权限错误 配置错误 InnoDB 恢复异常

这类问题时,第一个应该检查的通常就是 Error Log。

因此实际运维时可以形成一个习惯:

MySQL 出现异常,先查错误日志。


十五、Binlog:MySQL 数据恢复和复制的核心日志

Binlog 全称:

Binary Log

也就是二进制日志。

它由 MySQL Server 层产生。

Binlog 主要记录:

对数据库数据造成修改的事件。

例如:

INSERTUPDATEDELETECREATETABLEALTERTABLE

而类似:

SELECTSHOW

通常不会作为普通数据修改事件记录进去。


十六、Binlog 有什么作用?

Binlog 最重要的两个作用是:

1. 主从复制 2. 数据恢复

1. 主从复制

主库执行:

UPDATEuserSETname='Tom'WHEREid=1;

之后变化被记录到 Binlog。

从库获取主库 Binlog,再重放其中的事件:

Master ↓ Binlog ↓ Replica ↓ Relay Log ↓ 重放

最终实现数据同步。


2. 数据恢复

如果误删了数据:

DELETEFROMuser;

只要备份和 Binlog 策略合理,就可以通过:

全量备份 + Binlog

实现时间点恢复。

这也是生产数据库必须认真规划 Binlog 的原因之一。


十七、Binlog 的三种格式

Binlog 经典的三种日志格式分别为:

STATEMENT ROW MIXED

1. STATEMENT

STATEMENT 记录执行过的 SQL。

例如:

UPDATEuserSETmoney=money+100WHEREid=1;

Binlog 中主要记录这条 SQL。

优点:

日志量相对较小

缺点是某些依赖上下文、随机函数或者环境差异的 SQL 可能产生复制一致性问题。


2. ROW

ROW 模式重点记录:

哪些行发生了怎样的变化。

它不依赖从库重新“理解”原 SQL 的业务语义。

优点:

复制更加可靠 数据一致性更好

缺点:

大量数据更新时 Binlog 可能明显增大

例如:

UPDATEuserSETstatus=1;

如果修改 100 万行,ROW 模式需要记录大量行变化。


3. MIXED

MIXED 可以理解为:

STATEMENT + ROW

MySQL 根据具体 SQL 情况选择适合的日志形式。


十八、如何查看 Binlog 是否开启?

可以使用:

SHOWVARIABLESLIKE'%log_bin%';

重点关注:

log_bin log_bin_basename log_bin_index

含义分别可以理解为:

log_bin 是否启用 Binlog log_bin_basename Binlog 文件基础路径 log_bin_index Binlog 索引文件

查看当前 Binlog 状态时,也可以使用对应版本支持的状态命令。

查看具体日志事件,例如:

SHOWBINLOG EVENTSIN'binlog.000010';

在服务器命令行还可以利用:

mysqlbinlog binlog.000010

解析 Binlog。


十九、Slow Query Log:定位慢 SQL 的重要工具

对于数据库性能优化来说,慢查询日志非常重要。

它会记录执行时间超过指定阈值的 SQL。

首先查看:

SHOWVARIABLESLIKE'%slow_query%';

常见变量包括:

slow_query_log slow_query_log_file

查看慢查询阈值:

SHOWVARIABLESLIKE'long_query_time';

例如:

long_query_time = 2

意味着执行时间达到相应条件的 SQL 可以被纳入慢查询分析范围。


1. 临时开启慢查询日志

例如:

SETGLOBALslow_query_log=ON;

调整慢查询阈值:

SETGLOBALlong_query_time=2;

如果希望长期生效,通常应该写入 MySQL 配置文件。

例如:

[mysqld] slow_query_log=ON slow_query_log_file=/usr/local/mysql/data/mysql-slow.log long_query_time=2

修改后按照实际环境使配置生效。


2. 如何验证慢查询日志?

可以人为执行一条耗时 SQL,例如:

SELECTSLEEP(3);

然后检查慢日志。

日志中通常能够看到:

执行时间 用户 主机 Query_time Lock_time Rows_sent Rows_examined SQL

这些数据对 SQL 性能诊断非常有帮助。

例如:

Query_time 很大 Rows_examined 非常大 Rows_sent 很小

往往意味着:

数据库扫描了大量数据,但真正返回的数据非常少。

这种 SQL 就值得重点检查索引设计和执行计划。


二十、mysqldumpslow:快速分析慢日志

当慢查询日志非常大时,人工查看效率很低。

可以使用:

mysqldumpslow mysql-slow.log

进行初步聚合分析。

在生产环境中,慢查询日志还经常会结合:

pt-query-digest Performance Schema EXPLAIN EXPLAIN ANALYZE

进行进一步分析。

完整的 SQL 优化链路通常是:


二十一、General Log:记录几乎所有数据库操作

General Log 又叫:

全量日志 / 通用查询日志

它可以记录连接到 MySQL 后执行的大量操作,包括:

SELECTSHOWINSERTUPDATEDELETE

查看配置:

SHOWVARIABLESLIKE'%general_log%';

开启:

SETGLOBALgeneral_log=ON;

General Log 在问题诊断时很有价值,但它的日志量可能非常大。

因此生产环境通常:

不建议长时间无目的开启 General Log。

否则容易产生:

大量磁盘 IO 日志快速膨胀 额外性能开销

更适合临时排查问题。


二十二、Relay Log:主从复制中的中继日志

Relay Log 主要出现在 MySQL 复制体系中的从库一侧。

传统复制流程可以抽象成:

因此:

Binlog:主库产生 Relay Log:从库复制过程中使用

两者不能混为一谈。

可以查看与 Relay Log 相关的参数,例如:

SHOWVARIABLESLIKE'%relay%';

其中可能包含:

relay_log relay_log_index relay_log_purge relay_log_recovery

等配置。


二十三、PID 文件

MySQL Server 启动之后,本质上也是操作系统中的一个进程。

系统需要记录:

mysqld 的进程 ID

这通常通过 PID 文件实现。

可以查看:

SHOWVARIABLESLIKE'%pid%';

例如:

pid_file

对应文件中通常保存一个数字:

44764

这个数字就是 MySQL Server 对应进程的 PID。

PID 文件对于:

服务管理 进程控制 启动停止 状态检查

都有一定作用。


二十四、Socket 文件

Linux/Unix 系统下,客户端和本机 MySQL Server 之间除了 TCP/IP,还可以通过 Unix Socket 通信。

查看 Socket 文件位置:

SHOWVARIABLESLIKE'socket';

常见值类似:

/tmp/mysql.sock

例如本地执行:

mysql-uroot-p

某些情况下客户端默认就是通过:

Unix Socket

连接 MySQL。

因此当遇到:

Can't connect to local MySQL server through socket

这一类错误时,就应该检查:

MySQL 是否启动 socket 文件是否存在 客户端和服务端 socket 路径是否一致 文件权限是否正常

二十五、表结构元数据发生了什么变化?

在较早版本的 MySQL 中,表结构信息会和.frm文件联系在一起。

例如过去一张表可能对应:

table.frm table.ibd

其中.frm用于保存表结构定义。

但进入 MySQL 8.0 后,元数据管理方式发生了重大变化。

MySQL 8 使用事务型数据字典,将大量数据库对象的元数据信息统一管理起来,不再继续依赖传统.frm文件作为普通表定义的核心存储方式。

因此学习 MySQL 文件结构时必须注意版本差异。


二十六、MySQL 8.0 学习时一定要注意“版本问题”

MySQL 的底层实现一直在演进。

很多早期资料中的:

文件名 默认值 系统变量 日志管理方式 数据字典结构 复制术语

在新的 MySQL 版本中都可能发生变化。

尤其涉及:

Redo Log 参数 .frm 文件 复制相关命令 默认认证插件 默认字符集

时,更应该确认自己当前使用的版本。

可以先执行:

SELECTVERSION();

再针对当前版本查看:

SHOWVARIABLES;

避免直接照搬其他版本的配置。

对于生产环境,更应该以实际版本的官方文档和SHOW VARIABLES结果为准。


二十七、把所有核心日志放在一起理解

最后将 MySQL 中几个最容易混淆的日志统一梳理一下。

日志主要作用典型使用场景
Redo Log保证事务持久性、崩溃恢复MySQL 异常宕机恢复
Undo回滚、历史版本MVCC、事务回滚
Binlog记录数据变更事件主从复制、数据恢复
Relay Log保存从主库获取的复制事件从库复制
Error Log记录启动运行错误故障排查
Slow Query Log记录慢 SQLSQL 性能优化
General Log记录数据库操作临时问题诊断

如果觉得日志很多,可以这样记:

Redo → 数据库崩了怎么恢复 Undo → 数据改了怎么撤回、怎么看旧版本 Binlog → 数据库曾经做过哪些修改 Relay Log → 从库准备执行哪些复制事件 Error Log → MySQL 到底哪里报错了 Slow Log → 到底是哪条 SQL 慢 General Log → MySQL 最近执行了什么

二十八、InnoDB 存储体系全景图

将本文内容串起来,可以形成这样一个整体认识:

同时外围还存在:

Error Log Slow Query Log General Log Relay Log PID Socket 配置文件

共同构成一个完整的 MySQL 运行环境。


总结

理解 InnoDB,不能只停留在:

SELECTINSERTUPDATEDELETE

更重要的是理解 SQL 背后发生了什么。

从存储层面来看:

Tablespace → Segment → Extent → Page → Row

其中Page 是 InnoDB 最核心的存储管理单位之一

从事务机制来看:

Redo Log → 保证崩溃恢复和持久性 Undo → 支持事务回滚和 MVCC

从 MySQL Server 层来看:

Binlog → 支持复制和数据恢复

从运维角度来看:

Error Log → 排查异常 Slow Query Log → 定位慢 SQL General Log → 临时追踪数据库操作 Relay Log → 支撑复制

真正理解这些组件之后,再学习:

Buffer Pool B+Tree 索引 MVCC 事务隔离 脏页刷新 Checkpoint 主从复制 SQL 优化

就会容易很多。

因为它们本质上都建立在 InnoDB 的存储结构和日志体系之上。


若有转载,请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/164188642

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询