InnoDB 内存结构
如下是 InnoDB 内存和磁盘结构图,左边是内存结构
缓冲池(Buffer Pool)
缓冲池是 InnoDB 主内存的一块区域,里面缓存了经常操作的磁盘数据,在执行增删查改操作时,会先操作缓冲池中的数据(若缓冲池中没有数据,则先从磁盘加载并写入缓冲池),然后再以一定频率刷新到磁盘,从而减少磁盘 IO,提高效率
更改缓冲区(Change Buffer)
在 8.0 版本后引入(之前叫做插入缓冲区),针对非唯一的非聚簇索引页(对唯一索引、主键索引不生效),在执行 DML(增删改)语句时,如果所需数据不在 Buffer Pool 中,不会直接操作磁盘,而是将数据变更缓冲在 Change Buffer 中,在之后读取数据时,再将数据合并到 Buffer Pool 中,最后将合并后的数据刷新到磁盘
因为对于非聚簇索引,插入通常是以随机的方式,且更新和删除也通常是针对两个不相邻的索引页,如果每一次操作都进行磁盘 IO ,效率较低,故先在缓冲池中合并处理
自适应哈希索引(Adaptive Hash Index)
无需人工操作,系统根据情况自动完成,用于优化 Buffer Pool 的查询,InnoDB 会监控对表上各个索引页的查询,如果发现 hash 索引能够提高查询速度,则自动建立 hash 索引
日志缓冲区(Log Buffer)
用于保存要写入到磁盘中的日志数据(redo log 、undo log),默认大小为 16MB ,日志缓冲区的日志会定期刷新到磁盘中,节约磁盘 IO
通过 innodb_flush_log_at_trx_commit 参数配置日志刷新到磁盘的时机,它可以取 0、1、2,默认为 1
- 0:每秒将日志写入并刷新到磁盘一次
- 1:日志在每次事务提交时写入并刷新到磁盘
- 2:日志在每次事务提交后写入,并每秒刷新到磁盘一次
InnoDB 后台线程
后台线程的作用是刷新缓冲池中的数据,保证缓冲池中缓存是最新的数据。将已修改的数据文件刷新到磁盘文件。保证在数据库发生异常时可以恢复到正常状态
Master Thread
核心后台线程,负责调度其它线程,将缓冲池的数据异步刷新到磁盘当中,保证数据的一致性,以及脏页刷新、合并插入缓存,undo 页回收
IO Thread
InnoDB 中使用 AIO(Asynchronous I/O,异步非阻塞I/O)来处理 IO 请求,IO Thread 负责 IO 请求的回调
Purge Thread
用于回收事务已经提交的 undo log ,事务提交后 undo log 就没有用了
Page Cleaner Thread
协助 Master Thread 进行脏页刷新,减轻 Master Thread 压力,减少阻塞
InnoDB 事务原理
事务原理,也就是如何保证事务的四大特性:原子性、一致性、隔离性和持久性
其中,原子性、一致性和持久性,是基于 Redo 和 Undo 实现的
而隔离性是通过锁和 MVCC 实现的
Redo Log(重做日志)
Redo Log 记录事务提交时数据页的物理修改,用来实现事务的持久性
Redo Log 由两部分组成,分别是 Redo Log Buffer(重做日志缓冲) 和 Redo Log File(重做日志文件),前者在内存中,后者在磁盘中
当事务中执行 DML 语句是,会先修改 Buffer Pool 中的数据,并将修改信息记录在 Redo Log Buffer 中,事务提交后将 Redo Log Buffer 中的修改信息持久化到磁盘的 Redo Log File 中,在刷新脏页到磁盘时,如果发生错误,可以从磁盘的 Redo Log File 中进行数据恢复,以保证事务的持久性
Redo Log Buffer 的修改信息持久化到磁盘,是一个日志追加过程(顺序 IO),性能较高
Undo Log(回滚日志)
Undo Log 记录数据被修改前的数据,是一种逻辑日志
当 delete 一条记录时,Undo Log 中会多一条对应的 insert 记录,当 update 一条记录时,Undo Log 会多一条相反的记录,当执行 rollback 时,就可以从 Undo Log 中读取记录并回滚
MVCC(Multi-Version Concurrency Control)
MVCC,多版本并发控制,指维护一个数据的多个版本,使得读写没有冲突
当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁,如 select lock in share mode (共享锁), select for update; update; insert; delete (排他锁)这些操作都是一种当前读
快照读
默认 select 操作就是快照读,即不加锁的非阻塞读,读取的是数据的可见版本
- RC:每次 select 都生成一个快照读
- RR:开启事务后的 select 才是快照读
- Serializable:快照读退化成当前读
记录隐藏字段
对于每张表,除了用户创建的字段外,还包含着如下隐藏字段
隐藏字段 | 说明 |
---|---|
DB_TRX_ID | 最后一次操作该记录的事务的id |
DB_ROLL_PTR | 指向该记录上一个版本记录的指针 |
DB_ROW_ID | 隐藏主键,如果表没有主键会自动生成该字段 |
Undo Log
Undo Log 日志在事务提交后可以被删除,但不一定被立即删除
当 insert 时,产生的 Undo Log 日志只在回滚时需要,当事务提交后可以被立即删除
当 update 、delete 时,产生的 Undo Log 日志在回滚和快照读时均需要,故不会被立即删除