假事务之名,深入研究UNDO与REDO

 “有道无术,术尚可求;有术无道,止于术”。今天让我们一起来看看DBA+社群联合发起人郭耀龙大师如何布道。     

专家简介

  

假事务之名,深入研究UNDO与REDO
郭耀龙

DBA+社群联合发起人

 

超过5年Oracle数据库经验,服务于大型制造业、银行、*、电信、电力等行业,曾主导某大型制造业的16核心系统从10g向11g平稳演进,擅长Oracle数据库架构规划、性能调整、故障诊断、SQL优化,熟悉Oracle RAC及MAA架构,对大型IT系统的Oracle数据库运维有较丰富的经验。

 

 

假事务之名,深入研究UNDO与REDO

 

本文主要讲述关于undo、redo的一些内容。由于undo、redo内容非常多,短时间内难以讲诉清楚,故若水三千,我们只取一瓢,我将从Oracle事务切入,分析undo、redo在事务中的作用。

假事务之名,深入研究UNDO与REDO

 

分享一句出自《道德经》里的话,我做了一个曲解,即:“道”理解为原理;“术”理解为实践、操作,就是说如果我们懂得了事物的原理,那么实践性的东西我们是可以培养和训练的,但是如果我们只懂得表面的操作,而不懂原理,那我们就只能停留在事物的表层,如果遇到新的情况,就难以应对。我认为做DBA也是一样,要能够理解Oracle的原理,才能处理一些深层次的问题,而不是在google无结果后就缴械投降。本篇文章的主要内容就是布道。

 

目录 

 

1、Undo在事务中的作用

  • 解析undo段头结构

  • 解析undo块、undo chain结构

2、Redo在事务中的作用

  • 解析redo结构、undo受redo保护的实质、CV对数据块的作用

  • 理解快速提交机制、delete实质

 


 

最近连续遇到3个由于ORA-600错误导致数据库无法启动的情况,其中两个都是由于异常关机后导致无法启动,这种错误大部分情况是与redo、undo相关,但是怎样来定位问题,怎样解决?这就需要了解Oracle redo、undo的原理,定位问题的方向一般都是解读alert日志、trace日志、或者在mount阶段使用一些跟踪事件,比如10013、10015、10046等进行辅助分析。

 

当然还有最主要的一招,查MOS,MOS上有专门针对600错误的搜索入口,在这里根据错误代码的第一个参数进行匹配查找:

 

假事务之名,深入研究UNDO与REDO

 

但如果这里匹配不上,或者MOS上给出的解决办法无效,就还是得回到使用trace日志等分析定位问题,但是这里的trace的解读可能会是拦路虎,怎样去解读trace不是今晚的主题,不做深入,当然不同的trace解读的方法也不尽相同,但是我自己有个体验,就是对Oracle的一些原理和数据结构理解越透彻,就越能读懂trace文件,我们只需要读懂其中的一些关键点,其余可以进行猜测,就足以解决问题,就像英语的阅读理解,只需要读懂1/3的内容,就能解答2/3的问题。这里扯的有点远了,我们回到今晚主题,希望通过今晚的分享能够让大家对undo、redo在Oracle事务中的作用有一定了解,并通过对undo、redo的部分结构的解析,让大家深入Oracle内部,在后续处理相关问题时能够有所帮助。

 

首先,先说下我对事务的理解。Oracle数据库根本上是一个程序,跟其他的应用系统程序无差别,应用系统的程序如果没有业务,那程序代码就无意义,Oracle如果没有事务运行,那Oracle代码也就无意义,所以,事务对于Oracle就像业务对于应用系统一样,是Oracle的灵魂,从这个意义上看,Oracle实例可以看做是用一段代码在维护很多事务运行,事务是oracle实例运行的核心任务,事务产生的数据就是db(控制文件、system文件等可看作内部事务产生)。个人理解,仅供参考。

 

下面描述一下oracle事务的一个简单过程

 

1、在事务开始前,会申请redo资源、undo资源; redo的申请主要是要获取记录redo的内存资源,会涉及到redo allocation latch等资源的申请, undo资源申请是要获取到一个undo段用来存储undo数据(IMU机制会稍有不同);

 

2、在undo段头的事务表中申请一个槽位,记录事务信息,这些相关信息也会以xid等形式写入到数据块的事务槽中;

 

3、undo段头的事务表指向可用的undo块,undo块用于存储具体的undo信息;

 

4、事务开始,进行增、删、改、查等操作,redo记录相关信息、undo也记录相关信息,在事务涉及到的行头还会设置行锁标记;

 

5、事务提交或回滚,结束事务。修改undo段头事务表信息,尽可能的修改相关数据块的事务槽信息、行锁信息,将相关事务信息写入redo log文件。

 

上面只是粗略的一个描述,其中涉及到很多概念,比如undo段头、unod块、事务槽、行锁标记、redo记录等,这些东西具体长什么样?是怎样工作的呢?这里让我想起了一句话:爱情就像鬼一样,谁都听过,但谁也没见过。下面我们就通过实验来解析上面提到的这些概念,看一看是否真的有爱情。

 

 1  Undo在事务中的作用 

 

1.1 解析undo段头结构

 

假事务之名,深入研究UNDO与REDO

 

上面的实验修改了表中的两条记录,且这两条记录是存放在不同的块中先dump被修改的两个数据块进行观察

 

假事务之名,深入研究UNDO与REDO

 

另外一个数据块

 

假事务之名,深入研究UNDO与REDO

 

前面提到的事务槽和行锁标记都出现了,我们看到爱情了!!!

 

事务槽中涉及到几个重要的结构,下面进行下解释:

 

xid=Undo.Segment.Number+Transaction.Table.Slot.Number+Wrap

 

uba = Address of the last undo block used + Sequence + Last Entry in UNDO record map

 

这两个重要结构简单的理解就是,xid指向了事务使用的undo段号、事务表中的槽位号、以及槽位被覆盖的次数;uba指向事务使用的最后一个undo块、seq值、以及最后一条undo记录。

 

事务槽中还有一个flag段,这个段有不同的取值,代表事务的不同状态,可以通过修改这个标志实现手工提交事务,常见的取值有以下几种:

 

----    事务是活动的,或者在块清除前提交事务

C---    事务已经提交并且清除了行锁定

--U-    快速提交

 

再回到前面的两个块的dump数据可以发现,两个数据块的事务槽中都有一个未提交的事务,都是使用了第二个事务槽,两个块的xid完全相同,即两个块使用的是同一个undo段中的同一个事务表槽位,uba的前两部分也完全相同,即使用的是同一个undo块,第三部分不一样,说明两个块的前镜像使用了两个条undo record进行记录。

 

从xid信息可以知道,事务使用的是第6号回滚段,下面dump 6号undo段头进行观察:

 

假事务之名,深入研究UNDO与REDO

 

假事务之名,深入研究UNDO与REDO

 

上图就是undo段头中的事务表,又看到爱情了!!!

 

下面对其中的几个重要列进行解释:

 

index:表示slot 编号

 

state:表示状态,9 表示事务inactive,10表示active.

 

Uel:跟提交列表有关

 

Dba:表示该事务对应的undo block dba地址

 

1.2 解析undo块、undo chain结构

 

根据前面两个块的xid(0x0006.01f.000001a5)可知,事务使用的是1f号槽位,从前面事务表的图中可以看出,该槽位的state列为10,即事务未提交,其对应的undo block的地址为c03fba。

 

将该dba地址进行转换:

 

假事务之名,深入研究UNDO与REDO

 

使用的undo块是3号文件的16314号块,下面dump该块进行观察:

 

假事务之名,深入研究UNDO与REDO

 

这里有两个重要结构,irb指向事务的最后一条undo记录,即回滚的起点,icl指向事务的第一条undo记录,即回滚的终点。

 

从前面数据块dump的uba(0x00c03fba.0072.15、0x00c03fba.0072.14)的第三部分可知,事务对应的undo记录为14、15,观察这两条记录:

 

假事务之名,深入研究UNDO与REDO

 

假事务之名,深入研究UNDO与REDO

 

这里需要注意三点:

 

  • redo记录中的rci指向的是事务的前一条undo记录;

  • 前镜像的内容中只记录了被修改列内容;

  • undo块中存在着一条链表,这个链表见下图:

 

假事务之名,深入研究UNDO与REDO

 

这就是undo chain的一部分,与事务的混滚操作有关,undo块的irb指向事务undo record的最后一条记录 ,该记录中的rci指向前一个undo record记录,以此类推,最后一个undo record的ric为空,表示事务的起点,也是回滚的终点。

 

下图是完整的undo chain:

 

假事务之名,深入研究UNDO与REDO

 

这里大家可以扩展思考一下,oracle的save point是如何实现的,是不是会与undo chain有关?如果修改rci值是不是可以实现回滚部分事务?

 

下面我们来看一个网上流传比较广的一个图:

 

假事务之名,深入研究UNDO与REDO

 

从前面我们的实验可以看出,这个图是有歧义的,undo镜像不是块级别的,所以不是一个数据块对应一个undo块,undo镜像其实是列级别的,只有被更改的列才会被记录。

 

Undo在事务中的工作方式我们就先分析到这。

 

 2  Redo在事务中的作用 

 

2.1 解析redo结构、undo受redo保护的实质、CV对数据块的作用

 

下面来看一看redo是如何工作的:

 

假事务之名,深入研究UNDO与REDO

 

接下来dump 405号块进行观察(这里只选取表数据部分)

 

假事务之名,深入研究UNDO与REDO

 

使用BBED观察DBA+这列的行头信息

 

假事务之名,深入研究UNDO与REDO

 

下面删除其中的两条数据(这两条数据是位于不同的块中)

 

假事务之名,深入研究UNDO与REDO

 

Dump上面两个scn之间的redo进行观察

 

假事务之名,深入研究UNDO与REDO

 

假事务之名,深入研究UNDO与REDO

 

假事务之名,深入研究UNDO与REDO

 

下面对redo dump进行分析:

 

1、 redo log是以CHANGE VECTOR为最小单位构成的,就是上面的CHANGE #n部分;

 

2、 一个REDO RECORD包含多个CV(CHANGE VECTOR);

 

3、 OP表示操作类型,不同的值表示不同的操作类型;

 

4、 redo中包含了前镜像,这就是redo保护undo的实质;

 

5、 上面的操作涉及两个块,但是只有一条redo record,所以redo record是可以包含多个块的,但是一个CV只能针对一个块,CV是一个数据块块版本演进的结果,CV只能向前推进数据块的版本,不能后退,对于回滚操作,会由于undo的应用而生成新的CV,这个CV依然是推进数据块版本,要使数据块版本回退的唯一方法是介质恢复。

 

2.2 理解快速提价机制、delete实质

 

下面再次dump 405号块(包含DBA+的数据块)

 

假事务之名,深入研究UNDO与REDO

 

注意,这里nrow显示还有两行数据,但是删除行的数据没有在dump中显示;行锁标记也未释放,但是事务已经提交了,这就是Oracle的快速提交、和延迟块清除机制,只是保证修改undo段头事务表信息,块头和行头信息不一定进行修改。

 

那么delete到底发生了什么?下面用bbed进行观察:

 

假事务之名,深入研究UNDO与REDO

 

发现被删除的数据依然在块中,只是行头标记被修改,这就是delete的实质。所以在数据被覆盖之前是可以通过修改行头标记恢复被delete的数据的。

 

还记得我们开始的那句话吗?爱情就像鬼一样,谁都听过,但谁也没见过。通过上面的实验,我们应该看到了一些东西。真爱还是有的!

 

时间,教会了我们很多东西。有些我们曾经认为根本没有的,后来发现,它确确实实存在着,而有些我们深信不疑的,后来却明白,根本就没有。比如,爱情…

 


本文来自云栖社区合作伙伴"DBAplus",原文发布时间:2015-11-20

上一篇:[算法系列之十三]Rabin-Karp字符串查找算法


下一篇:[Android Pro] android 禁用和开启四大组件的方法(setComponentEnabledSetting )