innoDB存储引擎

88 阅读9分钟

逻辑存储结构

表空间(ibd文件)

一个MySQL实例可对应多个表空间,用于存储记录、索引等数据。

  • 分为数据段(叶子节点段)、索引段(非叶子节点段)、回滚段 。
  • InnoDB是索引组织表,数据段即B+树叶子节点,索引段即B+树非叶子节点,段用于管理多个区。

区(Extent)

  • 表空间的单元结构,每个区大小为1M 。
  • InnoDB存储引擎页大小默认16K,一个区有64个连续的页。

页(Page)

  • InnoDB存储引擎磁盘管理最小单元,默认大小16KB 。
  • 为保证页连续性,每次从磁盘申请4 - 5个区。

行(Row)

  • InnoDB数据按行存放 。
  • Trx_id:记录改动时,对应事务id赋值给该隐藏列。
  • Roll_pointer:记录改动时,旧版本写入undo日志,该隐藏列像指针,可找到修改前信息。

架构

内存架构

Buffer Pool

概述

Buffer Pool是内存区域,用于缓存磁盘上常操作的真实数据。执行增删改查时,先操作缓存数据(无则从磁盘加载并缓存),再定时刷新到磁盘,减少磁盘I/O。

Buffer Pool管理

以Page为单位,底层用链表管理Page。Page按状态分三种:

  • free page:空闲未使用。
  • clean page:已使用,数据未修改。
  • dirty page:已使用,数据修改,与磁盘数据不一致。

Change Buffer

定义

Change Buffer即更改缓冲区,针对非唯一二级索引。执行DML语句时,若相关数据页不在Buffer Pool,不直接操作磁盘,而是将数据变更存于Change Buffer,待数据被读取时,合并数据到Buffer Pool并刷新到磁盘。

意义

非唯一二级索引数据插入、删除和更新顺序相对随机,频繁操作磁盘会产生大量I/O。Change Buffer可在缓冲池中合并处理变更,减少磁盘I/O 。

Adaptive Hash Index

概述

Adaptive Hash Index即自适应hash索引,用于优化对Buffer Pool数据的查询。InnoDB存储引擎监控表索引页查询情况,若发现hash索引能提升查询速度,就自动建立,无需人工干预。

相关参数

adaptive_hash_index,可以通过show variables like "%adaptive_hash_index"来查看是否开启

Log Buffer

概述

Log Buffer即日志缓冲区,用于保存待写入磁盘的redo log、undo log等日志数据,默认大小16MB ,日志定期刷新到磁盘。对于涉及大量行更新、插入、删除的事务,增大其大小可节省磁盘I/O。

相关参数
  • innodb_log_buffer_size:用于设置缓冲区大小。
  • innodb_flush_log_at_trx_commit:控制日志刷新到磁盘的时机,取值及含义:
    • 1:每次事务提交时写入并刷新到磁盘。
    • 0:每秒将日志写入并刷新到磁盘一次。
    • 2:每次事务提交后写入,并每秒刷新到磁盘一次。

磁盘架构

System Tablespace(系统表空间)

  • 存储区域:是更改缓冲区的存储区域。若表在系统表空间创建,还可能包含表和索引数据。在MySQL 5.x版本中,还包含InnoDB数据字典、undo log等。
  • 相关参数:innodb_data_file_path 。

File-Per-Table Tablespaces(独立表空间)

  • 存储内容:每个表的文件表空间包含单个InnoDB表的数据和索引,存储在文件系统的单个数据文件中。
  • 相关参数:innodb_file_per_table 。

General Tablespaces(通用表空间)

通过CREATE TABLESPACE语法创建,创建表时可指定使用该表空间,语法示例:

CREATE TABLESPACE table_space_name ADD DATAFILE 'file_name' ENGINE = engine_name;
CREATE TABLE xxx... TABLESPACE ts_name;

Undo Tablespaces(撤销表空间)

MySQL实例初始化时自动创建两个默认undo表空间(初始大小16M ),用于存储undo log日志。

Temporary Tablespaces(临时表空间)

InnoDB使用会话临时表空间和全局临时表空间,用于存储用户创建的临时表等数据。

Doublewrite Buffer Files(双写缓冲区)

InnoDB引擎将数据页从Buffer Pool刷新到磁盘前,先写入双写缓冲区文件(如#ib_16384_0.dblwr、#ib_16384_1.dblwr ),用于系统异常时恢复数据。

Redo Log(重做日志)

  • 作用:实现事务持久性。
  • 组成:由重做日志缓冲(内存中)和重做日志文件(磁盘中,如ib_logfile0、ib_logfile1 )组成。事务提交后,修改信息存入日志,用于脏页刷新出错时的数据恢复,以循环方式写入重做日志文件。

后台线程

后台线程用于同步内存缓冲区及磁盘区,主要有5种

Master Thread

核心后台线程,负责调度其他线程,异步将缓冲池数据刷新到磁盘,维持数据一致性,涵盖脏页刷新、合并插入缓存、undo页回收等工作。

IO Thread

InnoDB用AIO处理IO请求提升性能,IO Thread负责这些请求的回调。

线程类型默认个数职责
Read thread4负责读操作
Write thread4负责写操作
Log thread1将日志缓冲区刷新到磁盘
Insert buffer thread1将写缓冲区内容刷新到磁盘

Purge Thread

用于回收事务提交后不再使用的undo log 。

Page Cleaner Thread

协助Master Thread将脏页刷新到磁盘,减轻其工作压力,减少阻塞。

事务

概述

事务的特性有4个,分别是:

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

其中原子性、一致性、持久性主要是通过redo log和undo log来实现的,而隔离性则是通过锁和mvcc来实现的

redo log

redo log概述

redo log即重做日志,记录事务提交时数据页的物理修改,用于实现事务的持久性。由重做日志缓冲(在内存)和重做日志文件(在磁盘 )组成。事务提交后,修改信息存入日志,用于脏页刷新出错时的数据恢复。

工作流程

在一个事务内执行updatedelete等操作并提交事务后,相关数据页变化先存于Buffer Pool,同时写入Redolog buffer 。采用WAL(Write - Ahead Logging,预写日志)机制,优先记录日志到磁盘的重做日志文件(如ib_logfile0/1 ),而数据页不一定立刻刷新到磁盘(.ibd文件) ,保证事务提交后数据修改能持久化存储,若后续刷新脏页出错,可依据重做日志恢复数据。

性能

为什么不在事务提交的时候直接提交Buffer Pool中的数据到磁盘中?因为多条写入的数据一般都是随机io,性能比较低;而将日志写入磁盘则是添加新的日志,是顺序io,性能优于随机io。

undo log

功能

undo log即回滚日志,记录数据修改前信息,作用是提供回滚和支持MVCC(多版本并发控制),用于实现原子性 。

与redo log 区别

redo log是物理日志,记录数据页物理修改;undo log是逻辑日志 。比如delete记录时,undo log记一条insert记录;update时,记一条反向update记录,执行rollback时依此回滚。

生命周期与存储

  • 销毁:事务执行产生undo log ,提交时不立即删除,因可能用于MVCC。
  • 存储:采用段方式管理记录,存于rollback segment回滚段,回滚段含1024个undo log segment 。

MVCC

基本概念

当前读

读取记录最新版本,读取时对记录加锁,防止其他并发事务修改。像select ... lock in share mode(共享锁)、select ... for updateupdateinsertdelete(排他锁)操作都属于当前读 。

快照读

简单select(不加锁)操作,读取记录数据的可见版本,可能是历史数据,是非阻塞读。

不同隔离级别下特点

  • Read Committed:每次select都生成一个快照读。
  • Repeatable Read:开启事务后第一个select语句触发快照读。
  • Serializable:快照读退化为当前读。

MVCC(多版本并发控制)

全称Multi-Version Concurrency Control,维护数据多个版本,避免读写冲突。快照读为MySQL实现MVCC提供非阻塞读功能。

实现依赖数据库记录的三个隐式字段、undo log日志、readView 。

隐藏字段

在每张表创建时,mysql会为这张表自动创建2~3个隐藏字段

隐藏字段含义
DB_TRX_ID记录插入或最后一次修改该记录的事务ID 。
DB_ROLL_PTR回滚指针,配合undo log,指向上一个版本 。
DB_ROW_ID若表无指定主键,生成此隐藏主键。

undo log

undo log产生时机与用途

undo log即回滚日志,在insertupdatedelete操作时产生,用于数据回滚。

不同操作下的生命周期

  • insert操作:产生的undo log仅在回滚时需要,事务提交后可立即删除。
  • update和delete操作:产生的undo log不仅回滚时需要,快照读时也需用到,不会在事务提交后立即删除。

undo log版本链

当不同事务或相同事务对同一条记录进行修改时,该记录的undo log会生成记录版本链表 。链表头部是最新的旧记录,尾部是最早的旧记录。 这一机制在实现MVCC(多版本并发控制)时发挥重要作用,可用于确定快照读时数据的可见版本等场景。

ReadView

ReadView定义

ReadView(读视图)是快照读SQL执行时MVCC(多版本并发控制)提取数据的依据,记录并维护系统当前活跃(未提交)的事务id 。

ReadView核心字段

字段含义
m_ids当前活跃的事务ID集合
min_trx_id最小活跃事务ID
max_trx_id预分配事务ID,当前最大事务ID + 1(事务ID自增)
creator_trx_idReadView创建者的事务ID

ReadView版本链数据访问规则

trx_id为当前事务ID,依据以下规则判断能否访问版本链数据:

  1. trx_id == creator_trx_id ,可访问该版本,意味着数据由当前事务更改。
  2. trx_id < min_trx_id ,可访问该版本,表明数据已提交。
  3. trx_id > max_trx_id ,不可访问该版本,说明事务在ReadView生成后开启。
  4. min_trx_id <= trx_id <= max_trx_id ,且trx_id不在m_ids中,可访问该版本,说明数据已提交。

不同隔离级别下ReadView生成时机

  • READ COMMITTED:事务中每次执行快照读都生成ReadView。
  • REPEATABLE READ:事务中首次执行快照读生成ReadView,后续复用。