【Mysql技术内幕InnoDB存储引擎】读书笔记

一、存储引擎

1、InnoDB引擎

设计目标是面向在线事务(OLTP)处理的应用。

支持事务、行级锁、通过多版本并发控制(MVCC)支持高并发、提供一致性非锁定读、next-key locking避免幻读、主键聚集索引

2、MyISAM引擎

设计目标是面向OLAP应用。

不支持事务、不支持行锁、表锁设计、支持全文索引

3、其他存储引擎

二、InnoDB体系结构

1、线程模型

InnoDB存储引擎是多线程模型,后台有多个不同的线程,用于处理不同的任务。

  • Master Thread:核心线程,将缓冲池中的数据异步刷新到磁盘
  • IO Thread:负责io请求的回调处理
  • Purge Thread:负责undo页的回收
  • Page Cleaner Thread:负责脏页的刷新

1.1、Master Thread

内部由多个循环组成。包括主循环(loop),后台循环(background loop)

主循环每隔一秒的操作

  • 把日志缓冲刷新到磁盘,即使这个事务还没有提交。很好的解释了再大的事务提交时间也很短
  • 合并插入缓冲
  • 至多刷新n(可配置,自动调整,1.2版本之后)个脏页到磁盘
  • 没有用户活动,切换到background loop

主循环每隔10秒的操作

  • 合并最多5个插入缓冲
  • 缓冲日志刷新到磁盘
  • 删除无用的undo页
  • 刷新脏页到磁盘(超过70%,刷新100页,没超过70%,刷新10页)

2、内存模型

2.1、缓冲池

InnoDB是基于磁盘的存储系统,为了弥补cpu和磁盘性能的差距,将从磁盘读出的数据保存在内存中,下次读取先从缓冲池中读取。有数据更新也先更新缓冲池的数据,通过checkpoint机制写回磁盘。缓冲池中包括索引页、数据页、undo页、插入缓存、锁信息等

2.2、缓冲池管理(LRU List)

最近做少使用算法,最频繁使用的页在List前端,最少使用的页在List末尾。当缓冲池容量不足容纳新数据时,先从尾部释放数据页。新数据插入在List的midpoint(List的5/8,对朴素LRU的优化,朴素LRU插入List头部。避免大量一次性查询把频繁使用的页刷出缓冲池)

2.3、脏页管理(Flush List)

当数据被更新,缓冲池中的数据首先被更新,修改之后的页称为脏页。脏页会保存到Flush List中,通过checkpoint机制把脏页数据写回磁盘

2.4、重做日志(redo log)缓冲

首先把重做日志信息存入缓冲区,然后按照一定频率同步到重做日志文件中。以下三种情况都会触发重做日志缓存同步到重做日志文件:

  • Master Thread 每隔一秒刷新
  • 每个事务提交时
  • 重做日志缓冲池容量达到阈值,一般是1/2

2.5、check point技术

为了防止宕机导致事务未提交信息丢失,在事务提交时,先把数据保存到重做日志(redo log)中,再修改页。保证了持久性(D)

发生宕机,重启之后自动从重做日志中恢复数据。

但是这里有以下问题:

  • 重做日志过大,宕机重启恢复数据太慢
  • 重做日志不能无限扩容,需要循环利用
  • 重做日志不可用怎么办

check point就是为了解决这些问题:

  • 缩短数据库恢复时间
  • 重做日志不可用,刷新脏页
  • 缓冲池不够用,将脏页刷新到磁盘

check point触发时机:

  • Master Thread check point。每隔一秒触发一次
  • LRU List check point。保证LRU List中有100个空闲页,如果清理的页中有脏页,触发check point 强制刷新脏页数据到磁盘
  • Dirty Page too mush check point。脏页太多,超过阈值,触发check point 强制刷新脏页数据到磁盘

3、关键特性

3.1、插入缓存

(1)为什么需要插入缓存?

我们知道索引分为聚集索引和非聚集索引。

聚集索引一般是自增的唯一id,页中的数据记录按顺序存放,写入的时候不需要随机读取其他页中的数据,写入速度很快(如果用UUID作为主键,写入速度会很慢,每次写入都需要随机读)

实际应用中,一张表往往还有非聚集索引的存在。非聚集索引叶子节点的插入不是顺序的,需要离散的访问非聚集索引页,随机读取导致了插入数据的性能下降。插入缓存就是为了优化这种场景下的插入速度

(2)什么场景会触发插入缓存?

  • 索引是辅助索引
  • 索引不是唯一索引

对于非聚集索引的插入,会先判断非聚集索引页是否在缓冲池中,如果在缓冲池中,直接插入索引页,如果没在,先放入到insert buffer对象中,然后再以一定的频率把insert buffer中的数据和非聚集索引的叶子节点进行数据合并

(3)实现原理

insert buffer 的数据结构也是B+树,有记录要插入的时候,会对记录进行封装,按照记录的插入顺序进行编号,是顺序写入

3.2、两次写

(1)为什么需要插入两次写?

如果InnoDB正在写入某个页的数据到磁盘,正好写了一部分的时候宕机了。这种情况称为部分写失效,会导致数据丢失

(2)实现原理

double write由两部分组成。一部分是double write缓冲,一部分是物理磁盘连续共享空间。在刷新脏页数据的时候,先复制一份脏页数据到两次写缓存中,在顺序写入共享磁盘中(因为是顺序写性能影响不大)。最后写入数据存储磁盘中(离散写)

3.3、自适应hash索引优化

hash是非常快的查询方式,时间负责度为O(1)。而B+树的查找次数取决于树的高度。

如果一个页被频繁的访问,而且访问模式也相同(联合索引使用最左原则)。会自动针对这页数据根据缓冲池中的索引建立Hash索引提高查询速度

3.4、异步IO

可以在发出一个IO请求后,在发出另外的IO请求,没必要等待上一次的IO请求处理完成。把全部IO请求都发出,等待所有IO操作的完成,这就是AIO(Aysnc IO)

 三、文件

MySQL据库和InnoDB存储引擎有很多类型的文件,每种文件用处不同。主要有参数文件、sokcet文件、pid文件、日志文件、表结构文件、存储引擎文件

1、日志文件

  • 错误日志:记录启动运行以及关闭遇到的错误信息
  • 查询日志:记录所有的查询记录
  • 二进制文件(binlog):记录所有的数据更改记录。用于数据恢复和数据复制。事务中未提交的二进制日志会存放到缓冲中,等事务提交时直接将缓冲中的日志同步到二进制文件中。通过配置可以指定写缓冲多少次之后同步到磁盘,如果值设置大于1,当发生宕机时可能会丢失数据
  • 慢查询日志:查询时间超过指定阈值的记录

2、InnoDB存储引擎文件

  • 表空间文件:存储数据
  • 重做日志文件:存储事务日志

四、表

1、索引组织表

InnoDB中,表数据都是按照主键顺序组织存放的。每张表都有主键,如果没有显示的定义主键,会把唯一索引作为主键。如果唯一索引也没有,会自动创建6字节大小的指针作为主键

2、存储结构

所有数据都存放在表空间中,表空间又由段、区、页组成

  • 段:表空间由各个段组成。段的管理由引擎自身完成
  • 区:每个区大小为1M,由连续页组成
  • 页:磁盘管理的最小单位,默认每个页大小16k
  • 行:数据是按行进行存放的,一个页最多存放16k/2-200=7992行

五、索引

猜你喜欢

转载自www.cnblogs.com/wangzhongqiu/p/11447267.html