转载

InnoDB多版本学习

InnoDB是一个多版本存储引擎(multi-versioned storage engine),它保留发生改变的行旧版本信息来支持事务的并发性和回滚(rollback)特性。这些旧版本信息存储在回滚段(rollback segment),InnoDB使用在回滚段中的信息以执行在一个事务回滚中的undo操作,它还使用这些信息来建立行的早期版本数据来提供一致性读(consistent read)。

 

InnoDB内部,数据库为每行增加了三个字段:

DB_TRX_ID  长度6字节事务ID

记录最近一次发生insertupdate行数据操作的事务标识符,而对应delete操作实际上也不是直接删除,只是用一个bit位去标示删除标记。

DB_ROLL_PTR  长度7字节回滚指针

这个回滚指针指向回滚段(undo segment)中的回滚记录。如果行被更新,在行被update之前,undo log记录包含的信息必须根据被update的内容重建。

DB_ROW_ID  长度6字节行ID

该字段包含新行的Row Id,这个字段只在Insert操作时单调递增,DB_ROW_ID是需要一个互诉锁的才能产生。Innodb产生的clustered index包括Row ID.从另一方面来说,除了Clustered Index外,其它的索引不会包含Row Id

 

Undo log在回滚段中被分为insertupdate两块undo log

Insert undo log 仅仅在事务回滚时需要,并且当事务提交后能尽快丢弃。

update undo log则用于一致性读,但是只有当InnoDB分配的快照(为保证一致读在update undo log建立的较早版本的行数据)不再被事务调用时才被丢弃。

 

建议定期提交你的事务,包括那些仅发生一致性读的事务。否则InnoDB将无法丢弃update undo log,导致回滚段越来越大最终爆满undo所在表空间。

 

插入或者更新的数据对应的undo log记录在回滚段中的物理大小通常小于行本身。你可以通过这些信息来计算相关行在回滚段中所需要的空间。

 

Innodb的多版本设计中当执行delete语句时数据行并不会被立即删除,仅当update undo log记录被弃用并注明删除标识时,相应的行和索引才会被真正的删除。该操作被称为purgepurge操作非常快,通常可能delete语句发生之后随之发生。

 

如果对一张表进行频繁的小批量insertdeletepurge线程处理会产生延时,表会因为这些“死”行(没有发生物理删除)变得越来越大,而导致性能下降。这种情况,减少对新行的操作,并通过调整innodb_max_purge_lag参数为线程分配更多的资源。

InnoDB提供了两个参数innodb_max_purge_laginnodb_max_purge_lag_delay 来调整

innodb_max_purge_lag 默认为0(不延迟)。当purge线程落后时,控制INSERT, UPDATE, DELETE操作的延迟。

Innodb
事务系统维护事务列表,此事务列表包含被updatedelete操作标识为删除的索引记录,事务列表的长度表示
purge_lag的值。当purge_lag(事务列表的长度)大于innodb_max_purge_lag时,每个 INSERT, UPDATE,DELETE操作会延迟。

即当trx_sys->rseg_history_len超过了设置的innodb_max_purge_lag,就会影响DML操作最大delay不超过innodb_max_purge_lag_delay设置的时间,以microseconds来计算。

 

purge_lag可以通过show engine innodb status看到,如下:
InnoDB多版本学习

purge_lag的值为20.

 

谨慎调整innodb_max_purge_laginnodb_max_purge_lag_delay参数,依据现在的设计,可能你的实例的吞吐量会急剧的下降。

 

多版本和辅助索引

InnodbMVCC对待辅助索引和聚集索引不一样。

聚集索引clusteredindexes记录在其中可以就地更新(替换),它们有隐藏的系统列undo log entries(事务号+回滚指针),从早期版本的记录可以被重建。

辅助索引secondary indexes 不像聚集索引,辅助索引没有隐藏的系统列(事务号+回滚指针),也不能就地更新。

 

当更新一个辅助索引字段时,新的辅助索引插入,老的辅助索引记录被添加delete删除标记并且最终被purge。当一个辅助索引被标记删除或者辅助索引的页被新的事务更新了,Innodb从聚集索引中查找数据库记录。在聚集索引中,如果在一个读操作已开启,记录被更新,则检查该记录的DB_TRX_ID并且从undo log中检索正确版本的记录。

 

如果辅助索引被标记删除或者被更新了,此时,覆盖索引(covering index)技术是不可用的。Innodb从聚集索引中查找记录,而不是从索引结构返回值。

 

如果index condition pushdown (ICP)是开启的,并且查询的where条件部分能直接从索引中查找,MySQL server层仍然会将where条件这部分推到存储引擎然后对索引条件进行评估,使用这个索引把满足的行从表中读取出。如果找到匹配的行,即使已经被表示删除的记录,InnoDB会从聚集索引查找记录。

 

参考:

http://dev.mysql.com/doc/refman/5.7/en/innodb-multi-versioning.html

http://hedengcheng.com/?p=148

http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_max_purge_lag

http://mysql.taobao.org/monthly/2016/02/03/

正文到此结束
Loading...