基于这篇后续:理解MySQL的原理
🧠 一、MySQL Server 启动后到底加载了什么
当你执行:
bash
mysqld
或通过服务启动 MySQL 时,MySQL Server 会依次启动几个核心组件(类似 JVM 的启动阶段):
| 阶段 | 作用 |
|---|---|
| 1️⃣ 参数加载阶段 | 从配置文件(/etc/my.cnf 或 my.ini)读取参数,比如端口、数据目录、引擎类型、缓存大小等。 |
| 2️⃣ 存储引擎初始化 | 根据配置初始化 InnoDB、MyISAM 等存储引擎。 |
| 3️⃣ 系统表加载 | 从 mysql 系统库加载用户、权限、时区、字符集等系统表。 |
| 4️⃣ 日志系统初始化 | 打开 redo log、binlog、undo log 文件。 |
| 5️⃣ 等待客户端连接 | 开启监听端口(默认 3306),等待客户端发起 TCP 连接。 |
🏗️ 二、创建数据库与表时,MySQL 实际做了什么?
当你执行以下语句:
sql
CREATE DATABASE shop;
USE shop;
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
age INT
);
后台其实发生了这些事 👇
1. 创建数据库
MySQL 在数据目录(datadir)下创建一个文件夹:
/var/lib/mysql/shop/
这就是你的 shop 数据库对应的物理目录。
⚙️ 配置文件中的
datadir参数定义了所有数据库文件的存储根目录。
2. 创建表时,MySQL 会生成以下文件(以 InnoDB 为例)
假设你用的是 InnoDB(默认引擎),那么在 shop/ 目录下会生成:
shop/
├── user.frm # 表结构定义(表头元数据)
├── user.ibd # 表数据 + 索引存储文件(InnoDB 独立表空间)
📌 如果
innodb_file_per_table=OFF,那么数据不会存在user.ibd,而是存在共享表空间ibdata1中。
💾 三、插入数据时,MySQL 做了哪些底层操作?
假设执行:
sql
INSERT INTO user (name, age) VALUES ('Tom', 20);
后台流程如下(这是重点)👇👇👇
步骤 1:SQL 解析与执行计划生成(Server 层)
MySQL Server 负责 SQL 语法解析、优化、生成执行计划。
执行计划中确定:
- 目标表的引擎;
- 字段映射;
- 索引使用策略。
然后把具体操作交给存储引擎执行(如 InnoDB)。
步骤 2:InnoDB 缓冲池写入(Buffer Pool)
InnoDB 不会立刻把数据写入磁盘,而是:
- 先把记录写入内存中的 Buffer Pool;
- 在 Buffer Pool 中同时维护 数据页(Data Page) 和 索引页(Index Page)。
每个数据页大小为 16KB,一个表的数据会被拆成多个页。
步骤 3:记录 redo log(重做日志)
为了保证 事务持久性(D) ,InnoDB 同时写入一份日志到 redo log buffer 中,随后刷盘到磁盘的 redo 文件:
/var/lib/mysql/ib_logfile0
/var/lib/mysql/ib_logfile1
redo log 记录的是「物理层面的修改」,比如:
"第 123 号数据页第 456 个字节写入了 0x01"
即使系统崩溃,也能用 redo log 恢复数据。
步骤 4:写入 binlog(二进制日志)
Server 层还会写一份 binlog(二进制日志),记录逻辑操作:
INSERT INTO user (name, age) VALUES ('Tom', 20);
binlog 是用于 主从复制、数据恢复 的逻辑日志。
步骤 5:事务提交(两阶段提交)
为了保证 binlog 与 redo log 一致,InnoDB 采用了 两阶段提交:
| 阶段 | 动作 |
|---|---|
| 阶段1 | 写入 redo log 并标记为 prepare 状态 |
| 阶段2 | 写入 binlog,成功后标记 redo log 为 commit 状态 |
✅ 这样即使中途崩溃,也能判断事务是否已完成。
步骤 6:后台刷盘(Flush)
InnoDB 有专门的后台线程负责把内存中被修改过的页(dirty page)写入到 user.ibd 文件中。
所以实际的数据是以「页」为单位写入的,而不是一行一行写。
📂 四、MySQL 是怎么找到这些数据的?
当你执行查询:
sql
SELECT * FROM user WHERE id = 1;
流程如下:
-
SQL 解析器 → 分析 SQL;
-
优化器 → 判断是否使用索引;
-
执行器 → 通过主键索引 B+Tree 找到对应页;
-
InnoDB 引擎:
- 如果页在内存中(Buffer Pool),直接读取;
- 否则从
user.ibd文件加载对应页进内存;
-
返回结果。
🧩 五、存储格式总结(以 InnoDB 为例)
| 文件 | 内容 | 说明 |
|---|---|---|
.frm |
表结构定义 | Server 层定义字段信息 |
.ibd |
数据页 + 索引页 | InnoDB 独立表空间 |
ibdata1 |
系统表空间 | 存储共享元数据、Undo 信息 |
ib_logfile0/1 |
redo log 文件 | 持久化数据变更 |
mysql-bin.xxxxxx |
binlog 文件 | 主从同步、恢复用 |
⚠️ 六、总结一句话
MySQL 的数据最终都以「页(Page)」为单位写入
.ibd文件中,所有操作都会先经过 内存缓冲池(Buffer Pool) → redo log → 两阶段提交 → 后台刷盘 这一整套流程。