InnoDB 的架构分为内存结构、磁盘结构和后台线程三部分:内存负责缓存与缓冲,磁盘负责持久化,后台线程负责在两者之间搬运数据。
- MySQL 5.5 开始默认使用 InnoDB 存储引擎,它擅长事务处理、具有崩溃恢复特性。
- 架构图左侧为内存结构(In-Memory Structures),右侧为磁盘结构(On-Disk Structures)。
- 主内存中的一个区域,缓存磁盘上经常操作的真实数据。
- 执行增删改查时先操作缓冲池中的数据(没有则从磁盘加载并缓存),再以一定频率刷新到磁盘,从而减少磁盘 IO、加快处理速度。
- 缓冲池以 Page 为单位,底层采用链表管理 Page,按状态分三类:
| 类型 | 含义 |
|---|
| free page | 空闲 page,未被使用 |
| clean page | 被使用 page,数据没有被修改过 |
| dirty page | 脏页,被使用且数据被修改过,内存与磁盘数据不一致 |
- 针对非唯一二级索引页:执行 DML 时,如果这些数据 Page 不在 Buffer Pool 中,不直接操作磁盘,而是把变更存在 Change Buffer 中;未来数据被读取时,再合并恢复到 Buffer Pool,最后刷新到磁盘。
- 意义:二级索引通常非唯一,且以相对随机的顺序插入;删除、更新也可能影响索引树中不相邻的二级索引页。若每次都操作磁盘会造成大量磁盘 IO,有了 Change Buffer 就能在缓冲池中合并处理。
- 用于优化对 Buffer Pool 数据的查询。
- InnoDB 会监控对表上各索引页的查询,如果观察到建立 hash 索引可以提升速度,则自动建立,称为自适应 hash 索引。
- 无需人工干预,由系统根据情况自动完成;参数
adaptive_hash_index。
- 用来保存要写入磁盘的 log 日志数据(redo log、undo log),默认大小 16MB,会定期刷新到磁盘。
- 如果需要更新、插入或删除许多行的事务,增大日志缓冲区可以节省磁盘 IO。
- 参数:
innodb_log_buffer_size(缓冲区大小)、innodb_flush_log_at_trx_commit(刷新到磁盘的时机)。
innodb_flush_log_at_trx_commit | 行为 |
|---|
1(默认) | 日志在每次事务提交时写入并刷新到磁盘 |
0 | 每秒将日志写入并刷新到磁盘一次 |
2 | 日志在每次事务提交后写入,并每秒刷新到磁盘一次 |
| 结构 | 说明 | 相关参数 |
|---|
| System Tablespace | 系统表空间(ibdata1),是更改缓冲区的存储区域;表建在系统表空间而非每表 / 通用表空间时,也包含其表与索引数据(MySQL 5.x 还含数据字典、undo log) | innodb_data_file_path |
| File-Per-Table Tablespaces | 每表一个表空间文件,包含单个 InnoDB 表的数据和索引,存储在文件系统的单个数据文件中 | innodb_file_per_table |
| General Tablespaces | 通用表空间,需通过 CREATE TABLESPACE 创建,建表时可指定 | — |
| Undo Tablespaces | 撤销表空间,实例初始化时自动创建两个默认 undo 表空间(初始 16MB),存储 undo log | — |
| Temporary Tablespaces | 临时表空间,分会话临时表空间和全局临时表空间,存储用户创建的临时表等数据 | — |
| Doublewrite Buffer Files | 双写缓冲区,刷脏页到磁盘前先写入该文件,便于系统异常时恢复数据(ib_16384_0.dblwr、ib_16384_1.dblwr) | — |
| Redo Log | 重做日志,实现事务的持久性;由 redo log buffer(内存)与 redo log 文件(磁盘)组成,循环写入 ib_logfile0、ib_logfile1 | — |
CREATE TABLESPACE ts_name ADD DATAFILE 'file_name' ENGINE = InnoDB;
CREATE TABLE tb_user(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
) TABLESPACE ts_name;
InnoDB 将数据页从 Buffer Pool 刷新到磁盘前,先写入双写缓冲区文件;如果写入过程中系统异常,重启后可以从该文件恢复数据页,避免「页断裂」。
| 线程 | 职责 |
|---|
| Master Thread | 核心后台线程,负责调度其他线程;将缓冲池数据异步刷新到磁盘,保持数据一致性;还包括脏页刷新、合并插入缓存、undo 页回收 |
| IO Thread | InnoDB 大量使用 AIO 处理 IO 请求,IO Thread 负责这些请求的回调 |
| Purge Thread | 回收事务已经提交的 undo log(提交后 undo log 可能不再需要) |
| Page Cleaner Thread | 协助 Master Thread 刷新脏页到磁盘,减轻 Master Thread 压力、减少阻塞 |
IO Thread 按类型细分:
| 线程类型 | 默认个数 | 职责 |
|---|
| Read thread | 4 | 读操作 |
| Write thread | 4 | 写操作 |
| Log thread | 1 | 将日志缓冲区刷新到磁盘 |
| Insert buffer thread | 1 | 将写缓冲区内容刷新到磁盘 |
SHOW ENGINE INNODB STATUS;
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'innodb_log_buffer_size';
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
CREATE TABLESPACE ts_name ADD DATAFILE 'ts_name.ibd' ENGINE = InnoDB;
CREATE TABLE tb_user(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(20)
) TABLESPACE ts_name;
| 结构 | 一句话 |
|---|
| Buffer Pool | 缓存真实数据页,分 free / clean / dirty |
| Change Buffer | 缓存非唯一二级索引的变更,减少随机 IO |
| Adaptive Hash Index | 系统自动建立,加速等值查询 |
| Log Buffer | 暂存 redo / undo log,默认 16MB |
| Doublewrite | 刷脏页前先写,防页断裂 |
| Redo Log | 循环写 ib_logfile0/1,保证持久性 |