点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!Undo log用来记录数据修改的前映像。Undo log位于undo segments中,每个实例有多个undo segments,第一个undo segment位于system表空间中,其余的undo segment 位于undo表空间中。当事务需要回滚时,需要从undo log中获取数据修改的前映像,以便于将数据恢复到修改前的状态。
当一个事务需要读取的数据正在被另一个事务修改时,为了避免脏读,需要利用undo log构造出数据块被修改前的一致性的数据块。
当实例崩溃重启后,需要通过undo log将未提交的事务回滚,使实例恢复到崩溃前的一致性状态。
如下通过实验详细分析下DML三种操作insert、update、delete时undo log记录的内容。查询v$transaction视图,此视图记录了事务和undo相关的信息,通过此视图undo的信息找到记录上述修改操作的undo块。上一步之所以不提交事务是因为事务提交后,事务信息会从此视图移除,无法定位undo信息。xid列标识事务ID,UBAFIL标识undo所在的文件号,UBABLK标识undo块号。打开trace文件,可以看到导出的是6号文件的897号块。UNDO BLK表明是undo块,xid是事务ID,由三部分组成,XIDUSN.XIDSLOT.XIDSQN,与v$transaction视图中的三个字段对应。cnt对应UBAREC。找到cnt: 0x18的记录条目,里面有ITL信息,以及数据修改前的值,col 1表示的是第二列,第一列为col 0,[10]表示此列有10个字节,53 7a 6c 53 64 76 6d 43 78 72是16进制,转换成ascII字符为SzlSdvmCxr,正好是修改前id=3的列A的值。经过上述分析,可以得出结论,update操作时,undo中记录的只是更新的字段的旧值,不更新的字段值不会记录。记录了两列信息,转换成文本后,正好是8 和name8。由此可见当执行delete语句时,undo中记录的是删除的行的所有字段的值。执行一条insert语句,记住编号100,表示这行数据在数据块中的位置。- KDO Op code: DRP --表示操作类型,DRP=delete row piece。
- bdba: 0x01800417 --对应的数据文件和块,转换成二进制,前10位为数据文件号,后22位为块号 ,6 号数据文件,1047号块。
- slot: 100(0x64) --行在数据块中的位置,与上面select出来的row number正好对应。
由此可见,当执行insert时,undo中只会记录回滚时需要的操作DRP,和数据行的位置。如果在同一个事务里,对某一行数据的某一个字段值进行了多次修改,如将name='a'修改为name='b',再改为name='c',最后改成name='d',此时undo中会记录每一次的修改信息呢,还是只记录最后一次修改的信息呢?- col 1: [ 1] 63 --转换成字符为c。
- rci 0x05 -- 指向同一个事务的上一条undo记录。
依次转换col 1的值为字符得到 c->b->a->name1,正好与更新的顺相反,依次撤销即可实现回滚。rci 0x00表示本事务的第一条记录。在同一事务里,对某一个字段值反复更新,undo会记录每次操作的前镜像值,即会记录中间结果。update、insert、delete操作时,undo中记录的信息不一样。
- insert时,只记录了插入数据在数据块中的位置。
- delete时,记录的是整行数据。insert记录的信息最少,update记录的信息居中,delete记录的信息最多。
执行delete操作需要更多的undo空间记录回滚信息,回滚时需要从undo中拷贝更多的数据到数据块中。因此,delete操作的代价最昂贵。