InnoDB 存储引擎
InnoDB 存储引擎
完整支持 ACID 事务的 Mysql 存储引擎 。
1 体系架构

1.1 内存池
InnoDB 存储引擎有多个内存块,组成了一个内存池。
- 维护线程需要访问的多个内部数据结构。
- 缓存磁盘上的数据,方便快速读取,修改之前也在这里缓存。
- 重做日志
redo log
缓存。

1.1.1 缓冲池
InnoDB 存储引擎是基于磁盘存储的,并将记录按页的方式管理,由于磁盘与 cpu 的数据相差过大,通过使用缓冲区(内存)提高整体性能。
读取页的操作时,首先从磁盘读到页放入缓冲池中,下次读取直接从缓冲池中读取。
修改数据库中的页操作时,先修改缓冲池中的页,然后以一定频率将已修改的数据文件刷新到磁盘上,不是每次操作都会刷新。
缓冲池中包括 索引页、数据页、undo 页、插入缓冲、自适应哈希所有、锁信息、数据字典信息等。InnoDB 允许有多个缓冲池实例,每个页通过哈希分配到不同的缓冲池。
1.1.2 LRU
缓冲池通过 LRU 算法进行管理, 即最频繁使用的页放在最前端,最少使用的放在尾端,当缓冲池满后,首先释放尾端的页。
为了防止将热点数据从 LRU 中移除,InnoDB 在列表中加入midpoint位置,新读取到的页首先放在 LRU 列表的 midpoint
位置。midpoint
之前的为new列表,之后的为 old
列表。old
列表中的数据只有读取达到一定次数才会移动到 LRU 列表的热端。
脏页
在 LRU 列表中的页被修改后,该页变为脏页,即缓冲池中的页和磁盘上的页的数据发生了不一致。同时定义了 Flush 列表管理脏页信息。
1.1.3 重做日志缓冲
Redo log buffer
, 首先将重做日志信息放入缓冲区中,然后按一定频率将其刷新到重做日志中。
刷新策略
Master Thead
每秒刷新到重做文件中。- 每个事务提交时。
- 当重做日志小于1/2时。
1.1.4 额外的内存池
记录了一些 LRU、锁等信息。
1.2 CheckPoint
Write Ahead Log
策略,即当事务提交时,先写重做日志,再修改页。服务宕机时,可以通过重做日志完成数据的恢复,完成了事务的D(持久性)的要求。
由于重做日志不可能无限大,InnoDB 定义了 CheckPoint
检查点,CheckPoint
之前的页都刷新回磁盘。在需要恢复的时候只需对 CheckPoint
之后的重做日志进行恢复。
1.2.1 CheckPoint类型
Sharp CheckPoint
在发生数据库关闭的时候将所有的脏页刷新会磁盘。Fuzzy CheckPoint
:- 定时异步刷新。
- Page Cleaner线程检测LRU列表中是否有指定多的空闲页可用。
- 重做日志文件不可用,需要强制将一些页刷新回磁盘。
- 脏页数量太多。
1.3 后台线程
负责刷新内存池中的数据,保证缓冲池中的内存是最近的数据, 以及数据被刷新到磁盘中。保证在数据库发生异常的情况下能恢复到正常运行的状态。
后台有多个线程负责不同的任务。
1.3.1 Master Thread
将缓冲池中的数据异步刷新到磁盘,保证数据的一致性
- 日志缓冲刷新到磁盘
- 合并插入缓冲
- 刷新脏页到磁盘
- 删除无用的undo页
1.3.2 IO Thread
主要负责IO请求的回调处理,主要是 read、write、insert buffer、log 四个IO Thread。
1.3.3 Purge Thead
回收已经使用并分配的undo页
1.3.4 Page Cleaner Thread
将之前版本的脏页的刷新操作都放入单独的线程中执行
2 特性
2.1 插入缓冲
在 InnoDB 中,主键是唯一标识符,通常插入顺序是按照主键地都给的顺序插入的,所以插入聚集索引一般是顺序的,不需要磁盘的随机读取。而对于非聚集索引可能就不是按照顺序的了,插入数据时就需要离散地访问非聚集索引页,随机读取会影响插入的性能。
InnoDB 使用 Insert Buffer
,对于非聚集索引的插入或者更新,不是直接插入索引页中,先判断索引页是否在缓冲中,如果在直接更新,不在则放在Insert Buffer中。然后再以一定的频率进行 InsertBuffer
和辅助索引叶子节点的 merge
操作。
2.1.1 条件
- 索引是辅助索引。
- 索引不是唯一的(插入的时候不需要判断唯一性)。
2.2 两次写
保证数据页的可靠性。
2.2.1 问题
当数据库宕机时,如果 InnoDB 正在拍写入某个页到列表中,但是只写了一部分,就会发生部分页失效(也就是这个页已经损坏,不能通过重做日志恢复)。
2.2.2 Double write
在应用重做日志前,用户需要一个页的副本,当写入发生失效时,先通过页的副本来还原该页,再进行重做。

- 对缓冲池中的脏页刷新时,首先将脏页复制到内存中的
double write buffer
,然后通过double buffer
写入共享表空间的物理磁盘上,然后才进行同步磁盘。 - 如果写入磁盘过程中发生了崩溃,从共享表空间中的
double write
中找到该页的一个副本, 将其复制到表空间文件,再应用重做日志。
2.3 自适应哈希索引
InnoDB 会监控对标上个索引页的查询,如果判断建立哈希索引会提高速度,则建立哈希索引(自适应哈希索引)
数据库自优化的操作。
2.4 异步IO
数据库系统一般采用异步IO的方式处理磁盘操作。
- 异步io不需要阻塞等待查询结果。
- 可以进行IO merge 操作,若发现读的是同一个页,可能进行合并一次读取。
2.5 刷新邻接页
在刷新脏页的时候,如果发现该页所在区的其他页是脏页,那么一起被刷新。