第二章 InnoDB储存引擎(下)

2.6    InnoDB 关键特性

        InnoDB关键特性包括

  • 插入缓冲(Insert Buffer)
  • 两次写(Double Write)
  • 自适应哈希索引(Adaptive Hash Index)
  • 异步IO(Async IO)
  • 刷新邻接页(Flush Neighbor Page)

2.6.1 插入缓冲

1. Insert Buffer
         插入缓冲不是缓冲池的一部分。虽然缓冲池中有Insert Buffer信息,但是Insert Buffer和数据页一样,也是物理页的一个组成部分。
        InnoDB的Insert Buffer,对于非聚集索引页的插入或者更新操作,并不是每一次直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入,若不在,则放入到一个Insert Buffer对象中,且此时这个非聚集的索引并没有插入到叶子节点。然后再以一定的频率和情况进行Insert Buffer和辅助索引叶子节点的merge(合并)操作,这是通常能将多个插入合并到一个操作中(因为在一个索引页中),这样大大提高了对于非聚集索引插入的性能。使用Insert Buffer需要同时满足以下两个条件:
a):索引是辅助索引(secondary index)
b):索引不是唯一(unique)的

辅助索引不能是唯一的原因是 在插入缓冲时,数据库并不去查找索引页来判断插入的记录的唯一性。如果去查找又会有离散读取的情况发生,从而导致Insert Buffer失去了意义

        当在写密集的情况下,插入缓冲会占用过多的缓冲池内存,默认最大可以占用到1/2的缓冲池内存,这会给其他操作带来一定的影响。可以修改ibu_pool_size_per_max_size对插入缓冲的大小进行控制。

2. Change Buffer
        InnoDB1.0.x开始引入Change Buffer,可以将Change Buffer看做为Insert Buffer的升级。从这个版本开始,InnoDB可以对DML操作------INSERT、DELETE、UPDATE都进行缓冲,他们分别是Insert Buffer,Delete Buffer,Purge Buffer。Change Buffer适用的对象依然是非唯一的辅助索引
        对一条记录进行UPDATE操作可能分为两个过程:
        a):将记录标记为已删除
        b):真正将记录删除
        因此
Delete Buffer对应UPDATE操作的第一个过程,即将记录标记为删除。Purge Buffer对应UPDATE操作的第二个过程,即将记录真正的删除。

3. Insert Buffer的内部实现
        在MySQL4.1之前的版本中每张表有一颗Insert Buffer B+树。而在现在的版本中,全局只有一颗Insert Buffer B+树,负责对所有的表的辅助索引进行Insert Buffer。而这颗B+树存放在共享表空间中,默认也就是idbata1中。Insert Buffer是一颗B+树,因此其也是有叶节点和非叶节点组成。非叶节点存放的是查询的search key,search key一共占用九个字节

非叶节点中的search key.png

        search key一共占用9个字节,其中space 表示待插入记录所在的表空间id,在InnoDB中,每个表都有一个唯一的space id,space占用4个字节。marker占用1字节,它是用来兼容老版本的Insert Buffer。offset表示页所在的偏移量。占用4字节。

第二章 InnoDB储存引擎(下)_第1张图片
叶子节点中的记录

        space、marker、offset和非叶节点中的含义相同,一共占用9字节。第4个字段metadata占用4字节。从Insert Buffer叶子节点的第5列开始,就是实际插入记录的各个字段了。因此较之原记录,Insert Buffer B+树的叶子节点需要额外的13字节的开销

        因为启用了Insert Buffer,辅助索引页中的记录可能被插入到Insert Buffer B+树中,所以为了保证每次Merge Insert Buffer页必须成功,还需要有一个特殊的页来标记每个辅助索引页的可用空间。这个页的类型为Insert Buffer Bitmap。
        每个辅助索引页在Insert Buffer Bitmap页中占用4位。


第二章 InnoDB储存引擎(下)_第2张图片
每个辅助索引页在Insert Buffer Bitmap中存储的信息

4. Merge Insert Buffer
        Merge Insert Buffer 的操作可能发生在以下几种情况下:
        a):辅助索引页被读取到缓冲池时;
        b):Insert Buffer Bitmap页追踪到该辅助索引页已无可用空间时
        c):Master Thread

        第一种情况为当辅助索引被读取到缓冲池时,例如Select查询操作,这是需要检查Insert Buffer Bitmap页,然后确认该辅助索引页是否有记录存放于Insert Buffer B+树中。若有,则将Insert Buffer B+树中该页的记录插入到该辅助索引页中。
        Insert Buffer Bitmap页用来追踪每个辅助索引页的可用空间,并至少有1/32页的空间。若插入辅助索引记录检测到插入记录后可用空间会小于1/32页,则会强制进行合并操作,即强制读取辅助索引页,将Insert Buffer B+树中该页及待插入的记录插入到辅助索引中。
        Master Thread 线程中每秒或者每10秒会进行一次Merge Insert Buffer操作。

2.6.2 两次写
        如果说Insert Buffer带给InnoDB存储引擎的是性能上的提升,那么doublewrite(两次写)带来的则是数据页的可靠性
        当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到列表中,而这个页只写了一部分,比如16K的页,只写了4KB,之后就发生了宕机,这种情况成为部分写失效(partial page write)。doublewrite就能解决这个问题
        在应用一个重做日志之前,用户需要一个页的副本,当写入失效时,先通过页的副本来还原该页,再进行重做,这就是doublewrite

第二章 InnoDB储存引擎(下)_第3张图片
doublewrite 体系架构图

        doublewrite由两部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样是2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是通过memcpy函数将脏页先复制到内存中的double buffer中,之后通过doublewrite buffer再分为两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。
2.6.3 自适应哈希索引
        InnoDB会监控对表上各索引页的查询。如果观察到建立建立哈希索引可以带来速度的提升,则建立哈希索引,称之为自适应哈希索引(Adaptive Hash Index,AHI)。AHI是通过缓冲池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表改造哈希索引。InnoDB会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引。AHI有一个要求,即对这个页的连续访问模式必须是一样的。例如对于(a,b)这样的联合索引页,其访问模式可以是以下情况:

  • where a = xxx
  • where a = xxx and b = xxx
    访问模式一样是指查询的条件一样,若交替进行上述两种查询,那么InnoDB不会对该页构造AHI。此外,AHI还有如下要求:
  • 以该模式访问了100次
  • 页通过该模式访问了N次,其中N=页中记录*1/16
            值得注意的是,哈希索引只能用来搜索等值的查询,如select * from table where index_col = xxx ,而对于其他类型,如范围查找,是不能使用哈希索引的

2.6.4 异步IO
        为了提高磁盘操作性能,当前数据库都采用异步IO(Asyncchronous IO)的方式来处理磁盘操作。InnoDB存储引擎亦是如此。用户可以在发出一个IO请求后立即再发出另一个IO请求,当全部IO请求发送完毕之后,等待所有IO操作的完成,这就是AIO。AIO的另一个优势就是进行IO merge操作,也就是将多个IO合并成一个IO

2.6.5 刷新邻接页
        当刷新一个脏页时,InnoDB存储引擎会检测该页所在区的所有页,如果是脏页,那么一起进行刷新,该工作机制在传统机械磁盘下有着显著的优势。
2.6.6 启动、关闭与恢复
        InnoDB是MySQL数据库的存储引擎之一,因此InnoDB存储引擎的启动和关闭更准确的是指在MySQL实例的启动过程中对InnoDB存储引擎的处理过程。
        在关闭时,参数innodb_fast_shutdown影响着表的存储引擎为InnoDB的行为。该参数可取值为0、1、2,默认值是1

  • 0 表示在MySQL数据库关闭的时,InnoDB需要完成所有的full purge和merge insert buffer,并且将所有的脏页刷新回磁盘。
  • 1 表示不需要完成上述的full purge和merge insert buffer操作,但是在缓冲池中的一些数据脏页还是会刷新回磁盘
  • 2 表示不完成full purge和merge insert buffer操作,也不将缓冲池的数据脏页写回磁盘,而是将日志都写入日志文件。这样不会有任何事物的丢失,但是下次MySQL数据库启动时,会进行恢复操作(recovery)

        如果没有正常的关闭数据库,如用kill命令关闭数据库,在MySQL数据库运行中重启了服务器,或者在关闭数据库时,将参数innodb_fast_shutdown设为了2时,下次MySQL数据库启动时都会对InnoDB存储引擎的表进行恢复操作
        参数innodb_force_recovery影响了整个InnoDB存储引擎恢复的状况。该参数默认为0,代表当发生需要恢复时,进行所有的恢复操作,当不能进行有效恢复是,如数据页发生了corruption,MySQL数据库可能发生宕机(crash),并把错误写到错误日志中去。
        参数innodb_force_recovery还可以设置6个非零值:1~6,大的数字包含了前面所有小的数字表示的影响

  • 1 忽略检查到的corrupt页
  • 2 阻止Master Thread线程的运行。如Master Thread线程需要进行full purge操作,而这会导致crash
  • 3 不进行事务的回滚操作
  • 4 不进行插入缓冲的合并操作
  • 5 不查看撤销日志(Undo Log),InnoDB会将未提交的事务视为已提交
  • 6 不进行前滚操作

你可能感兴趣的:(第二章 InnoDB储存引擎(下))