MySQL InnoDB引擎
逻辑存储结构
表空间(ibd文件)
- 一个mysql实例可以对应多个表空间,用于存储记录、索引等数据
段
- 分为数据段,索引段和回滚段。
- 数据段是B+树的叶子节点,索引段是B+树的非叶子节点
- 用来管理多个分区
区
- 表空间的单元结构,每个区的大小为1M
- 默认情况下,一个区有64个连续页
页
- InnoDB存储引擎磁盘管理的最小单元,默认大小为16KB
- 为保证页的连续性,存储引擎每次申请4-5个区
行
架构
InnoDB擅长事务处理,具有崩溃恢复特性
事务原理
redo log
- 重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性
- 该日志文件由两部分组成:重做日志缓冲(redo log buffer)和重做日志文件(redo log file)
- 前者在内存中,后者才磁盘中
- 当事务提交之后会把所有修改信息都存到该日志文件中,发生错误时进行数据恢复
undo log
- 回滚日志,用于记录数据被修改前的信息,用于回滚和MVCC(多版本并发控制)
- 当INSERT的时候,产生的undo log只在回滚时需要,在事务提交后可被立即删除
- 当UPDATE、DELETE时,产生的undo log日志不仅在回滚时需要,快照读时也需要,不会被立即删除
- 是逻辑日志
例如:delete一条记录时,undo log会记录一条对应的insert记录
undo log销毁
undo log在事务执行时产生,事务提交时不会立即删除,这些日志还可能用与MVCC。
undo log存储
undo log采用段的方式进行管理和记录,存放在回滚段中,内部包含1K个undo log段
MVCC
基本概念
当前读
- 读的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会加锁。
如 SELECT … LOCK IN SHARE MODE/FOR UPDATE、UPDATE、INSERT、DELETE
快照读
- 快照读读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
- 不同级别对应的快照读时机:
隔离级别 | 快照读的版本 |
---|
Read Committed | 每次SELECT都生成一个快照读 |
Repeatable Read | 开启事务后第一个SELECT语句才是快照读的地方 |
Serializable | 快照读会退化为当前读 |
MVCC(多版本并发控制)
- 指维护一个数据的多个版本,使得读写操作没有冲突。
- 快照读为MySQL实现MVCC提供了一个非阻塞读功能。
- MVCC的实现,还需依赖数据库记录中的三个隐式字段、undo log、readView。
实现原理
记录当中的隐藏字段
字段名 | 含义 |
---|
DB_TRX_ID | 最近修改事务ID、记录插入这条数据或最后一次修改该数据的事务ID |
DB_ROLL_PTR | 回滚指针,指向这条记录的上一版本,用于配合undo log指向上一版本 |
DB_ROW_ID | 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段 |
undo log 版本链
- 不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链
- 链表的头部是最新的旧记录,链表的尾部是最早的旧记录
readview(读视图)
- 读视图是快照读SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的事务)id
readview四个核心字段
字段名 | 含义 |
---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(事务ID是自增) |
creator_trx_id | ReadView创建者的事务ID |
版本链数据访问规则
以该访问规则遍历版本链,直到遍历到符合访问规则的版本。
条件 | 访问规则 |
---|
trx_id = creator_trx_id | 说明数据是当前事务更改的,可访问该版本 |
trx_id < min_trx_id | 说明数据已经提交,可访问该版本 |
trx_id > max_trx_id | 说明该事务是在ReadView生成后才开启的,不可访问该版本 |
min_trx_id <= trx_id <= max_trx_id 且 trx_id不在m_ids中 | 说明数据已经提交,可访问该版本 |
生成ReadView的时机
隔离级别 | 生成时机 |
---|
READ COMMITTED | 在事务中每次执行快照读时生成ReadView |
REPEATABLE READ | 仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView |