《《MySQL运维内参》节选》要点:
本文介绍了《MySQL运维内参》节选,希望对您有用。如果有疑问,可以联系我们。
书接上文,本篇介绍日志管理的最后一部分.
在存储已经搞定之后,那么还需要继续研究一个要写入的UNDO日志记录的格式是什么样子的.关于记录格式,之前也介绍过InnoDB表中行记录(Compact)的格式,也介绍了REDO日志的记录格式,其实都是本着省空间、高效率的宗旨来设计的,那么对于UNDO记录也是一样,但是因为UNDO日志有多个类型,针对不同的类型,其格式也不尽相同,UNDO日志的类型有下面几种.
除了上面说到的Table ID信息、主键信息之外,还会包括一些公有的信息,比如回滚段指针、最近更新事务号,这样方便MVCC在回溯记录时可以找到以前的版本,关于MVCC的内容在这里就不详细展开了.
再回到记录格式.因为记录格式都不尽相同,所以这里只拿TRX_UNDO_INSERT_REC来举例说明,下图即为其格式.
每一个位置的解释如下.
从图中可以看到,很多位置的存储都是压缩存储的,所以上面第六点说到,列数据长度用的字节个数有可能是若干个,这决定于InnoDB所使用的压缩编码方式.
这里需要注意的一点是,与REDO日志记录存储不同,UNDO日志的存储,是不会跨页面的,所以在页面头中关于日志存储的开始位置和结束位置就至关重要了.
其他类型的回滚记录,这里就不再介绍了,大致结构是一样的,只不过内容可能不尽相同.
需要注意的一点是,假如一个表中有多个索引,在修改一行数据时,回滚日志中也只会记录聚簇索引中的信息,而其他二级索引是不会被记录的.这是因为聚簇索引和二级索引中的每一行都是一一对应的,所以不同操作对聚簇索引操作时,也都会对二级索引有相应的操作,这样就没必要对二级索引写回滚日志了.
(注:配图为2017.5.6 ACMUG上海活动分析嘉宾,微博美女DBA)
前面已经介绍过,UNDO日志的正确性是通过REDO的恢复来保证的,在REDO日志恢复完成之后,UNDO操作就可以安全地进行了.数据库启动过程中,执行了用于REDO恢复的函数recv_recovery_from_checkpoint_start之后,就可以处理UNDO的数据了,InnoDB通过函数trx_sys_init_at_db_start来将所有回滚段相关的128*1024个UNDO扫描出来(如果存在就找到,不存在就忽略),找到之后,每一个UNDO段的状态都已经清楚了,然后将它们都缓存起来.
然后再通过函数trx_lists_init_at_db_start依次处理每一个UNDO段,根据UNDO段的状态,决定后面将采取什么措施,如果状态为TRX_UNDO_PREPARED和TRX_UNDO_ACTIVE,则这个UNDO段是需要做回滚操作的,否则是不需要的.决定回滚需求之后,再将最多128*1024个UNDO段按照上面提到的TRX_UNDO_TRX_NO从大到小的顺序排序.
最后就在之前介绍关于InnoDB存储引擎启动时的函数recv_recovery_from_checkpoint_finish中,来做回滚的相关工作.在这个函数的最后可以看到以下内容.
它根据参数innodb_force_recovery来决定要不要做回滚操作,如果设置为3或3以上,就不回滚了,这样可能导致数据库逻辑上的不一致.
最终,InnoDB通过trx_rollback_or_clean_recovered来做回滚操作,通过扫描上面排序之后的链表,发现其还是以从大到小的顺序遍历,这个顺序很重要,因为UNDO是反向操作,所以应该是先处理新产生的事务,后处理老的事务,通过事务号来区分新老关系.
针对每一个UNDO段,InnoDB会将所有状态为ACTIVE的事务的UNDO日志扫描出来,然后一条一条地做回滚操作,UNDO日志记录格式已经明确,扫描所有的日志就变得非常简单,并且针对不同的操作,对应的回滚方式也已经清楚,等待所有的回滚段处理完成之后,整个数据库的回滚操作也就完成了.回滚过程如下图所示.
文章来自微信公众号:DBAce
转载请注明本页网址:
http://www.vephp.com/jiaocheng/4148.html