Innodb 多版本实现

    作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究

     Innodb是一个多版本的存储引擎,它可以把旧的行信息存到表空间中。这些旧的行信息存储到Innodb称为的回滚段的表空间中。

     Innodb为实现多版本,Innodb在每一行添加了三个列。一个6字节的DB_TRX_ID字段用来表示事务的Insert或是Update操作,对于Delete操作实际上也并不在直接删除,只是用一个Bit位去标识行被删除。另外,每行包括7字节的DB_ROLL_PTR字段,称为回滚指针(roll pointer)。这个回滚指针指向回滚段(undo segment)中的回滚记录。如果行被更新,那么回滚段中记录的信息足以使update操作加到update操作之间。最后还有一个6字节的DB_ROW_ID字段,该字段包含新行的Row Id,这个字段只在Insert操作时单纯的增加。DB_ROW_ID是需要一个互诉锁的才能产生。Innodb产生的clustered index包括Row ID.从另一方面来说,除了Clustered Index索引外,其它的索引不会包含Row Id.

     Innodb利用回滚段保存的信息完成事务的回滚。同样是为了读取早的版本行信息,通过回滚段中的信息达到一致性读。

       回滚段中的回滚日值可以区分为insert和update日值。Insert的回滚日值只需要一个事务回的信息,记录Insert的操作的事务就行,该回滚信息在事务提交后被丢弃。Update的回滚日值不但用来撤销事务,同时也为一致性读服务。在事务操作中,别的Session可以通过Update的回滚段信息达构建早期的版本,从来达到一致性读。

       对于Innodb的多版本是为达到一致性读,我们在使用Innodb时要养成一个习惯:要规律的提交我们的事务。另一方面,对于Innodb的回滚段中Update的回滚日值不能随着事务的提交而被丢弃,所以回滚段有可能增长很大,填满所有的表空间。

       回滚段的需求的物理大小通常比Insert和Update的行小的多,所以我们可以根据Insert,Update行的并发量来估算分配回滚段的大小。

    在Innodb的多版本设计中,Delete语句并不是直接物理的从数据中立即删除相应的行,只是做一个Bit位的标识。另外当Innodb删除相应的原行和行的索引信息时,回滚段中此行的Update回滚日值才会被清除。对于Delete操作的的删除我们称为静化(purge),这个操作是很快速的,正常情况下静化在SQL语句后按一定的顺序去执行删除操作。

    假设一个场景:当一个用户用小的批量插入和删除行操作在一个表,它有可能会造成静化操作的进程落后,从而造成表的增长的很大很大,使的磁盘的工作效率比较低了。这样就会出现恶劣的情况既使表只有该表只有10M的数据,也有可能使表空间增长到10G,当然里面有很多是即将过静化掉的行(dead row).基于这个原因,静化进程会造成新的行操作和分配资源的性能瓶颈。所以也要关注一下innodb_max_purge_lag这个参数的设定是不是合适。