最近在学习姜承尧老师的 InnoDB 的内容,然后觉得讲得特别好,其实很多时候关于 MySQL 的内容(或者说做的优化)都是基于 InnoDB 引擎的,这些专属的东西应该花时间去了解 InnoDB 而不是 MySQL (当然不是说 MySQL 不重要,不过了解原理比学会应用更有价值)。然后特别想挑一小段内容跟大家分享,如果有说得不对也希望指正!^_^
InnoDB 架构模型
内存池:
- 维护所有进程 /线程需要访问的多个内部数据结构
- 缓存磁盘上的数据,方便快速读取,同时在对磁盘文件的数据修改之前在这里缓存
- redo log 缓冲
后台线程:
- 负责刷新内存池中的数据,保证缓冲池中的内存缓存是最近的数据
- 将修改的数据文件刷到磁盘文件
- 保证发生异常的情况下 InnoDB 能够恢复到正常运行状态
内存
缓冲池
设置原因:CPU 与磁盘速度之间的鸿沟。
在数据库中读取页的操作,先从磁盘读取到缓冲池中,读取相同页的时候判断是否在缓冲池中直接命中。
缓冲池中缓存的数据页类型有:
- 索引页
- 数据页
- undo 页
- insert buffer
- 自适应哈希索引
- 引擎的锁信息
- 数据字典信息
缓冲池允许有多个,通过参数配置,默认为 1。
LRU List、Free List、Flush List
最频繁使用的页在 LRU 列表的前端,而最少使用的页在 LRU 列表的尾端。
InnoDB 中设置了midpoint位置,读取到新的页,虽然是“Recently Used”,但是先插入到 midpoint 位置而不是前端,默认配置下处于 LRU 列表长度的 5/8 处,midpoint 前的列表称为 new 列表,midpoint 后的列表称为 old 列表。使用 midpoint 优化的原因是在读取页的时候,因为会导致尾端的页被刷出 LRU 列表,如果直接在前端插入大量的页(一般为索引或扫描操作)会将 LRU 列表大量页刷出,而这部分插入的操作可能仅是一次性的,因此需要先将这些页放在 midpoint 位置,然后后续如果确实频繁使用再加入 LRU 列表的热端。
Free 列表表示可用的页,如果 Free 列表有可用的空闲页,就会将页从 Free 列表中删除、加入 LRU 列表中;如果没有,则要从 LRU 列表尾端淘汰,将内存分配给新的页。可以理解成 LRU 长度增加,Free 长度就减少,Free 没有的时候还需要插页面就需要从 LRU 淘汰。
在 LRU 列表中的页被修改后,称为 dirty page,缓冲区与磁盘中的数据不一致,这时候通过CHECKPOINT机制刷回磁盘,Flush 列表中的页即为脏页列表,脏页既存在于 LRU 列表中也存在与 Flush 列表中,前者保证页的可用性,后者管理页刷回磁盘。