InnoDB对于对于DML语句操作(如Update或Delete),事务提交时只需在缓冲池中完成操作,然后再通过Checkpoint将修改后的脏页数据刷新到磁盘。
InnoDB有两种Checkpoint
Sharp Checkpoint:数据库关闭时将所有脏页刷新回磁盘
Fuzzy Checkpoint:
重做日志是为了保证事务的原子性,持久性。(防止宕机后不一致)InnoDB采用Write Ahread Log策略,事务提交时,先写重做日志,再修改页。
数据库宕机重启时通过执行重做日志恢复数据。
但由于Checkpoint机制,数据库宕机重启并不需要重做所有的日志,因为Checkpoint之前的页都刷新到磁盘了,只需执行最新一次Checkpoint后的重做日志进行恢复,这样可以缩短数据库的恢复时间。
InnoDB中重做日志文件是循环使用的。当页被Checkpoint刷新到磁盘后,对应的重做日志就不需要使用 ,其空间可以被覆盖重用。
如果待写入的重做日志文件空间不可用(脏页还没有刷新到磁盘),就需要强制产生Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置。
InnoDB 1.2.x(MySql 5.6)后,FLUSH LRU LIST Checkpoint以及Async/Sync Flush Checkpoint操作放到Page Cleaner线程,以免阻塞用户线程。
磁盘分为顺序IO和随机IO,例如要插入数据到磁盘的两个地方A和B
数据存储
Mysql的数据存储是根据主键来顺序存储的。所以在插入数据的时候:
索引最好是有序的
索引存储
Mysql中主键本身也是索引,称为主索引(Primary index),其他索引称为辅助索引(secondary index)
如果一个表中有辅助索引,在插入数据的时候,除了存储数据,还需要建立索引。如果插入两条数据,主键是顺序的,但是有一个索引的数据是不顺序的,这样也会产生随机IO。(画磁盘扇区图)
Mysql的优化方法是加入插入缓冲:也就是先把索引放在缓冲池中,定期刷新到磁盘。这样可以减少随机IO的次数。例如插入两条数据,索引位置是相同的,如果分两次刷新到磁盘,就需要两次随机IO。如果合并为一次,只需要一次随机IO。
插入缓冲(Insert Buffer/Change Buffer):提升插入性能,change buffer是insert buffer的加强,insert buffer只针对insert有效,change buffering对insert、delete、update(delete+insert)、purge都有效。
Change buffer是作为buffer pool中的一部分存在。Innodb_change_buffering参数缓存所对应的操作:(update会被认为是delete+insert)
innodb_change_buffering,设置的值有:inserts、deletes、purges、changes(inserts和deletes)、all(默认)、none。
all: 默认值,缓存insert, delete, purges操作
none: 不缓存
inserts: 缓存insert操作
deletes: 缓存delete操作
changes: 缓存insert和delete操作
purges: 缓存后台执行的物理删除操作
可以通过参数控制其使用的大小:
innodb_change_buffer_max_size,默认是25%,即缓冲池的1/4。最大可设置为50%。*当MySQL实例中有大量的修改操作时,要考虑增大*innodb_change_buffer_max_size
只对于非聚集索引(非唯一)的插入和更新有效,对于每一次的插入不是写到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,如果在则直接插入;若不在,则先放到Insert Buffer 中,再按照一定的频率进行合并操作,再写回disk。这样通常能将多个插入合并到一个操作中,目的还是为了减少随机IO带来性能损耗。
插入缓冲需要条件:
可以通过engine status命令来查看插入缓冲的状态
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Double write缓存是位于系统表空间的存储区域,用来缓存InnoDB的数据页从innodb buffer pool中flush之后并写入到数据文件之前,所以当操作系统或者数据库进程在数据页写磁盘的过程中崩溃,Innodb可以在doublewrite缓存中找到数据页的备份而用来执行奔溃恢复。数据页写入到doublewrite缓存的动作所需要的IO消耗要小于写入到数据文件的消耗,因为此写入操作会以一次大的连续块的方式写入
在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是double write
doublewrite组成:
内存中的doublewrite buffer,大小2M。
物理磁盘上共享表空间中连续的128个页,即2个区(extend),大小同样为2M。
写入buffer过程:
对缓冲池的脏页进行刷新时,不是直接写磁盘
而是会通过memcpy()函数将脏页先复制到内存中的doublewrite buffer,
之后通过doublewrite 再分两次,每次1M顺序地写入共享表空间的物理磁盘上
在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。
写入表空间
恢复