InnoDB undo log解析(一)

在InnoDB存储引擎中,undo log用来完成事务的回滚以及MVCC的功能。但是InnoDB本身提供对于undo log的分析或者查询功能非常有限。用户仅能通过SHOW ENGINE INNODB STATUS中的History list length信息的值当前undo log在history列表中的数量。网上已经有些文章分析了undo log的存储结构,但很少对InnoDB的undo log进行解析。本博文将详细介绍InnoDB存储引擎中的undo log格式,使读者能更为深入了解其实现。

在InnoDB存储引擎中,undo log可分为以下两种类型:

  • insert undo log
  • update undo log

InnoDB undo log解析(一) - insidemysql - Inside MySQL

insert undo log是指在insert操作中产生的undo log。因为insert操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo log可以在事务提交后直接删除。不需要进行purge操作。insert undo log的格式如左图所示(点击可看原图)


图中*表示对存储的字段进行了压缩。insert undo log开始的前两个字节next记录的是下一个undo log的位置,通过该next的字节可以知道一个undo log所站的空间字节数。类似地,尾部的两个字节记录的是undo log的开始位置。type_cmpl占用一个字节,记录的是undo地类型,对于insert undo log,该值总是为11。undo_no记录事务的ID,table_id记录undo log所对应的表对象。这两个值都是用于进行压缩的。接着的部分记录了所有主键的列和值。在进行rollback操作时,根据这些值可以定位到具体的记录,然后进行删除即可。


InnoDB undo log解析(一) - insidemysql - Inside MySQL
 

update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行最后的删除。update undo log的结构如右图所示(点击可看原图)。


update undo log相对于之前介绍的insert undo log,记录的内容更多,所需占用的空间也更大。next、start、undo_no、table_id与之前介绍的insert undo log部分相同。这里的type_cmpl,由于update undo log本身还有分类,故其可能的值如下:

  • 12 (TRX_UNDO_UPD_EXIST_REC)
  • 13 (TRX_UNDO_UPD_DEL_REC)
  • 14 (TRX_UNDO_DEL_MARK_REC) 


undo log可以分为上述3种类型,其分别代表了更新non-delete-mark的记录,将delete的记录标记为not delete,将记录标记为delete。


紧接着的部分记录update_vector信息,update_vector表示update操作导致发生改变的列。每个修改的列信息都要记录的undo log中。对于不同的undo log类型,可能还需要记录对索引列所做的修改。


Oracle和Microsoft SQL Server数据库都由内部的数据字典来观察当前undo的信息,InnoDB存储引擎在这方面做得还是不够,DBA只能通过原理和经验来进行判断。InnoSQL对information_schema进行了扩展,添加了两张数据字典表,这样用户可以非常方便和快捷地查看undo的信息。


首先增加的数据字典表为INNODB_TRX_ROLLBACK_SEGMENT。顾名思义,这个数据字典表用来查看rollback segment(回滚段)。InnoDB 1.1版本开始,其一共有128个rollback segment,每个rollback segment支持1024个undo log段,因此一共支持128*1024个同时并发在线事务。而之前的版本仅有1个回滚段,故最大支持并发事务为1024。

例如,用户可以通过下面的命令来查看rollback segment所在的页(InnoDB 1.2版本之前,rollback segment都放在共享表空间内,故space值都为0。InnoDB 1.2版本开始支持独立的rollback segment表空间):

mysql> SELECT segment_id,space,page_no FROM INNODB_TRX_ROLLBACK_SEGMENT;

+------------+-------+---------+

| segment_id | space | page_no |

+------------+-------+---------+

|          0 |     0 |       6 |

|          1 |     0 |      45 |

|          2 |     0 |      46 |

......

128 rows in set (0.00 sec)


另一张数据字典表为INNODB_TRX_UNDO,用来记录事务对应的undo log,方便DBA和开发人员详细了解每个事务产生的undo量。下面将演示如和使用INNODB_TRX_UNDO表,首先根据如下代码创建测试表t。

CREATE TABLE t (

     a INT,

     b VARCHAR(32),

     PRIMARY KEY(a),

     KEY(b)

)ENGINE=InnoDB;


接着插入一条记录,并尝试通过INNODB_TRX_UNDO观察该事务的undo log的情况:

mysql> BEGIN;

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SELECT 1,’1’;

Query OK, 1 row affected (0.00 sec)

Records: 1  Duplicates: 0  Warnings: 0


mysql> SELECT * FROM information_schema.INNODB_TRX_UNDO\G;

*************************** 1. row ***************************

       trx_id: 3001

      rseg_id: 2

  undo_rec_no: 0

undo_rec_type: TRX_UNDO_INSERT_REC

         size: 12

        space: 0

      page_no: 334

       offset: 272

1 row in set (0.00 sec)


通过数据字典表可以看到,事务ID为3001,rollback segment的ID为2,因为是该条事务的第一个操作,故undo_rec_no为0。之后可以看到插入的类型为TRX_UNDO_INSERT_REC,表示是insert undo log。size表示undo log的大小,占用12字节。最后的space、page_no、offset表示undo log开始的位置。打开文件ibdata1,定位到页(334,272),并读取12字节,可得到如下内容:

01 1c 0b 00 16 04 80 00 00 01 01 10


上述就是undo log实际的内容,之前对于insert undo log格式的介绍,可以整理得到:

01 1c       # 下一个undo log的位置 272+12=0x011c

0b          # undo log的类型,TRX_UNDO_INSERT_REC为11

00          # undo log的记录,等同于undo_rec_no

16          # 表的ID

04          # 主键的长度

80 00 00 01 # 主键的内容

01 10       # undo log开始的偏移量,272=0x0110


此外,由于知道该undo log所在的rollback segment的ID为2,用户还可以通过数据字典表INNODB_TRX_ROLLBACK_SEGMENT来查看当前rollback segment的信息,如:

mysql> SELECT segment_id,insert_undo_list,insert_undo_cached

     -> FROM information_schema.INNODB_TRX_ROLLBACK_SEGMENT

     -> WHERE segment_id=2\G;

*************************** 1. row ***************************

        segment_id: 2

  insert_undo_list: 1

insert_undo_cached: 0

1 row in set (0.00 sec)


可以看到insert_undo_list为1。若这时进行事务的COMMIT操作,再查看该数据字典表:

mysql> COMMIT;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT segment_id,insert_undo_list,insert_undo_cached

     -> FROM information_schema.INNODB_TRX_ROLLBACK_SEGMENT

     -> WHERE segment_id=2\G;

*************************** 1. row ***************************

        segment_id: 2

  insert_undo_list: 0

insert_undo_cached: 1

1 row in set (0.00 sec)

可以发现,insert_undo_list变为0,而insert_undo_cached增加为1。这就是undo页重用,即下次再有事务需要向该rollback segment申请undo页时,可以直接使用该页。


update undo log较之insert undo log要复杂的多,因此将在第二篇中进行分析。so,预知后事如何,待听下回分解InnoDB undo log解析(一) - insidemysql - Inside MySQL



  登录后你可以发表评论,请先登录。 登录>>
2013-04-25 17:10
看大小的功能GJ啊,这个功能加上后拿不同事物隔离级别对undo大小影响来量化测一下.
有个问题,如果异常崩溃,如果之前有事务没提交,起来以后回滚会在实例可连通后继续进行,只不过这个表上的事务会有影响.这个情况下,能通过这个功能知道有多少待回滚的undo,来估算回滚时间么?
2013-04-26 10:41
 insidemysql  回复  SamN
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值