博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
InnoDB undo log解析(二)
阅读量:4106 次
发布时间:2019-05-25

本文共 14809 字,大约阅读时间需要 49 分钟。

在 中已经介绍了InnoDB undo log的组织结构,并通过一个示例并结合InnoSQL来分析insert undo log记录格式。本篇中介绍update undo log的记录格式。update undo log有以下三种类型:
 类型  十六进制值  说明
 TRX_UNDO_UPD_EXIST_REC  0x0c  更新一个not delete mark的记录
 TRX_UNDO_UPD_DEL_REC  0x0d  更新一个delete mark记录
 TRX_UNDO_DEL_MARK_REC  0x0e  将记录标记为delete mark
   
接着来看一个具体的例子,首先根据如下清单创建测试表t并导入测试数据:
CREATE TABLE t ( a INT, b VARCHAR(10), c INT, PRIMARY KEY(a), KEY(b)); INSERT INTO t SELECT 1,'1',1;
接着运行下面的事务,注意不要提交事务:
BEGIN        
;
DELETE FROM t WHERE a
=
1
;
mysql
>
 SELECT
*
FROM information_schema
.
INNODB_TRX_UNDO\G
;
***************************
1.
row
***************************
       trx_id
:
303
      rseg_id
:
4
  undo_rec_no
:
0
undo
_rec_type
:
TRX_UNDO_DEL_MARK_REC
         size
:
37
        space
:
0
      page_no
:
308
       offset
:
272
1
row
in
set
(
0.00
sec
)
打开共享表空间ibdata1并定位到page_no:308 offset:272的位置,得到如下的内容:
004d4110       
 
01
35
0e
00
0d
00
00
00
 
00
03
02
e0
83
00
00
01
 
|.
5.
.............|
004d4120
 
33
01
10
04
80
00
00
01
 
00
0b
00
04
80
00
00
01
 
|
3.
..............|
004d4130
 
03
01
31
01
10
00
00
00
 
00
00
00
00
00
00
00
00
 
|..
1.
............|
整理后可得:
 十六进值  说明
 01 35  undo log结束位置
 0e  undo log类型,TRX_UNDO_DEL_MARK_REC
 00  记录的info bit信息
 0d  表的ID
 00 00 00 03 02 e0   记录的隐藏事务ID列
 83 00 00 01 33 01 10  记录的隐藏回滚指针列
 04  主键长度
 80 00 00 01  主键值(a=1)
 00 0b  之后部分的字节数
 00  列的ID(列a)
 04  列占用的字节数
 80 00 00 01  列的值(a=1)
 03   列的ID(列b)
 01  列占用的字节数
 31  列的值(b=‘1’)
 01 10  undo log开始位置(0x0135-0x0110=37)
回滚事务,接着运行下面的例子:
mysql        
>
BEGIN
;
Query
OK
,
0
rows affected
(
0.00
sec
)
mysql
>
UPDATE t SET c
=
2
WHERE a
=
1
;
Query
OK
,
1
row affected
(
0.00
sec
)
Rows
matched
:
1
 
Changed
:
1
 
Warnings
:
0
mysql
>
SELECT
*
FROM information_schema
.
INNODB_TRX_UNDO\G
;
***************************
1.
row
***************************
       trx_id
:
308
      rseg_id
:
7
  undo_rec_no
:
0
undo
_rec_type
:
TRX_UNDO_UPD_EXIST_REC
         size
:
33
        space
:
0
      page_no
:
310
       offset
:
272
1
row
in
set
(
0.00
sec
)
按上述同样的方法整理undo log后可得:
十六进值  说明
 01 31  undo log结束位置
 1c  undo log类型,TRX_UNDO_UPD_EXIST_REC
 0d  表的ID
 00  记录的info bit信息
 00 00 00 03 02 e0   记录的隐藏事务ID列
 83 00 00 01 33 01 10  记录的隐藏回滚指针列
 04  主键长度
 80 00 00 01  主键值(a=1)
 01  update vector 的数量
 04  update vector保存的列ID(列c)
 04  列占用的字节数
 80 00 00 01  列的值(a=1)
 01 10   undo log开始位置(0x0135-0x0110=33)

这里undo log的类型为1c而不是0c这是因为这部分还保存了其他信息,这里1表示更新操作没有更新其他索引列。若更新辅助索引列b,如:
mysql       
>
BEGIN
;
Query
OK
,
0
rows affected
(
0.00
sec
)
mysql
>
UPDATE t SET b
=
'222'
WHERE a
=
1
;
Query
OK
,
1
row affected
(
0.00
sec
)
Rows
matched
:
1
 
Changed
:
1
 
Warnings
:
0
mysql
>
SELECT
*
FROM information_schema
.
INNODB_TRX_UNDO\G
;
***************************
1.
row
***************************
       trx_id
:
30A
      rseg_id
:
8
  undo_rec_no
:
0
undo
_rec_type
:
TRX_UNDO_UPD_EXIST_REC
         size
:
41
        space
:
0
      page_no
:
311
       offset
:
272
1
row
in
set
(
0.00
sec
)
可以看到这时undo log的类型还是
TRX_UNDO_UPD_EXIST_REC,但可以发现这时undo type的值为0c而非1c。此外,由于更新了列b,update vector会保存更新时记录列b的值,因此两次操作产生的undo log的量也不同。
何时会产生
TRX_UNDO_UPD_DEL_REC的undo log呢?这个类型表明是在delete mark的记录上进行更新,但是若事务已经提交则delete mark的记录是不允许更改的,其会等待purge线程进行删除。因此产生该类型的undo log发生应发生在同一事务中,如下面的情况:
mysql> BEGIN;       
Query OK, 0 rows affected (0.00 sec)
mysql> DELETE FROM t where a=1;
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO t SELECT 1,'2',2;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0
mysql>  SELECT * FROM information_schema.INNODB_TRX_UNDO ORDER BY undo_rec_no\G;
*************************** 1. row ***************************
       trx_id: 30E
      rseg_id: 10
  undo_rec_no: 0
undo_rec_type: TRX_UNDO_DEL_MARK_REC
         size: 37
        space: 0
      page_no: 314
       offset: 272
*************************** 2. row ***************************
       trx_id: 30E
      rseg_id: 10
  undo_rec_no: 1
undo_rec_type: TRX_UNDO_UPD_DEL_REC
         size: 46
        space: 0
      page_no: 314
       offset: 309
2 rows in set (0.00 sec)
可以看到事务的第二条SQL语句再次插入了主键值为1的记录,并且记录的大小没有发生变化,这意味着可以重用之前已经删除的部分,仅需对其他列的部分进行更新即可,而这就会产生
TRX_UNDO_UPD_DEL_REC的undo log。整理该undo log,最后可得:
十六进值  说明
 01 63  undo log结束位置
 0d  undo log类型,TRX_UNDO_UPD_EXIST_REC
 01  记录的info bit信息(1表示记录已经被delete mark)
 0d  表的ID 
 00 00 00 03 0e ca   记录的隐藏事务ID列
 00 00 01 33 01 10  记录的隐藏回滚指针列
 04  主键长度
 80 00 00 01  主键值(a=1)
 02  update vector 的数量
 03  update vector保存的列ID(列b)
 01  列占用的字节数
 31  列的值(b='1')
 04   update vector保存的列ID(列c)
 04  列占用的字节数
 80 00 00 01  列的值(c=1)
 00 0b  之后部分的字节数
 00  列的ID
 04   列占用的字节数
 80 00 00 01  列的值(a=1)
 03  列的ID
 01  列占用的字节数
 31  列的值(c=‘1’)
 01 35  开始位置
可以看到在某些情况下即便用过数据结构update vector记录发生变化的列,但还是需要记录发生更改的索引列的信息。源码中给出了明确的答案:
/* In the case of a delete marking, and also in the case of an update       
where any ordering field of any index changes, store the values of all
columns which occur as ordering fields in any index. This info is used
in the purge of old versions where we use it to build and search the
delete marked index records, to look if we can remove them from the
index tree. */
呼~~~ update undo log分析完了。可以尝试从源码文件trx0rec.c中的函数trx_undo_page_report_modify得到更为直接的答案。若希望自己分析undo log的内容,可以下载InnoSQL并进行尝试。下载地址:https://david-mysql-tools.googlecode.com/files/mysql-5.5.30-v1a-linux-x86_64.tar.gz
  登录后你可以发表评论,请先登录。
登录>>
2014-05-07 19:26
分析的很好! 
2013-05-13 13:27
作者能将delete,insert,update产生的redo log也做个总结不?这两篇文章非常不错!!!
2013-05-20 12:30
 回复 
InnoDB是physiology的redo 格式,redo类型很多,而且一次操作可能产生不止一个重做日志,所以要分析不是一件简单的事情。我这里的了工具可以查看redo log的信息,不过仅作开发调试使用
2013-08-28 17:34
 回复 
作者能写一篇关于character_set_client/connection/result的大作出来不?很喜欢你的文章!!
2013-08-28 17:35
 回复 
第一版已经买了,准备买第二版
2013-09-02 18:48
 回复 
你有什么疑问呢?
2013-09-02 18:48
 回复 
多谢
2013-05-16 15:19
jeppeter
文章写的不错。但有两个小的问题想问:
1, 关于你上面说的内容,是我理解的不对,还是你的笔误
page_no:308 offset:272这里的数据的时候,好像对不上节,
第三个字节,明明是0e,而你后面写成了1c,但在前一篇上面写着,
12 (TRX_UNDO_UPD_EXIST_REC)
所以, 这里是明显对不上。
第二个问题:
这里对于page_no:308 offset:中记录的值问题,你这里看到的值(a==1)
这个应该是1,而这里显示的是80 00 00 01,这个好像是也对不上。
(当然,innodb可能有什么特别处理,不一定在undo 中能找到答案)
第三个问题
对于整个undo log,要从压缩的角度讲,写的明显大,你提到的例子中
第一个字节明明是只有40-50个字节大小,但这里却在next要用上309的字节的
大小,如果是还有信息,但在物理层,没有看到这个,如果是为了以后添加,
那undo log本身只针对这一次,好像这一次不加,还有什么时候会加?
很希望请教请教。
2013-05-20 12:28
 回复 
jeppeter
1. 笔误,已经修正
2. 在计算机中,signed int占用4个字节,用80 00 00 01表示
3. 不好意思,没看懂你要表达的是什么意思
2013-05-28 13:57
jeppeter
 回复 
我第3个问题,就是,如果一个UNDO LOG 只有这么几十个字节大小 (从你这个分析来看,是这样的),但它指向下一个UNDO LOG却一般要一百多个字节。这 中间,有不少的空闲(可能我们不知道用途,暂时称之为空闲),那这个空闲是用什么呢?
如果是为了扩展,好像不必要留有这么大,而且UNDO LOG只有这一次会用到,如果是下一次了,就不是这个UNDO LOG了,如果是有其它用途,但我们现在看到的是0,所以,这个要309个字节的大小,与实际我们只分析了40~50个字节的大小,有巨大的差距。

转载地址:http://lcnsi.baihongyu.com/

你可能感兴趣的文章
聊聊gcc参数中的-I, -L和-l
查看>>
[C++基础]034_C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)
查看>>
C语言内存检测
查看>>
Linux epoll模型
查看>>
Linux select TCP并发服务器与客户端编程
查看>>
Linux系统编程——线程池
查看>>
Linux系统编程——线程池
查看>>
yfan.qiu linux硬链接与软链接
查看>>
Linux C++线程池实例
查看>>
shared_ptr简介以及常见问题
查看>>
c++11 你需要知道这些就够了
查看>>
c++11 你需要知道这些就够了
查看>>
shared_ptr的一些尴尬
查看>>
C++总结8——shared_ptr和weak_ptr智能指针
查看>>
c++写时拷贝1
查看>>
C++ 写时拷贝 2
查看>>
Linux网络编程---I/O复用模型之poll
查看>>
Java NIO详解
查看>>
单列模式-编写类ConfigManager读取属性文件
查看>>
java中float和double的区别
查看>>