专家简介
郭耀龙
DBA+社群联合发起人
超过5年Oracle数据库经验,服务于大型制造业、银行、*、电信、电力等行业,曾主导某大型制造业的16核心系统从10g向11g平稳演进,擅长Oracle数据库架构规划、性能调整、故障诊断、SQL优化,熟悉Oracle RAC及MAA架构,对大型IT系统的Oracle数据库运维有较丰富的经验。
本文主要讲述关于undo、redo的一些内容。由于undo、redo内容非常多,短时间内难以讲诉清楚,故若水三千,我们只取一瓢,我将从Oracle事务切入,分析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错误的搜索入口,在这里根据错误代码的第一个参数进行匹配查找:
但如果这里匹配不上,或者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段头结构
上面的实验修改了表中的两条记录,且这两条记录是存放在不同的块中先dump被修改的两个数据块进行观察
另外一个数据块
前面提到的事务槽和行锁标记都出现了,我们看到爱情了!!!
事务槽中涉及到几个重要的结构,下面进行下解释:
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段头中的事务表,又看到爱情了!!!
下面对其中的几个重要列进行解释:
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块是3号文件的16314号块,下面dump该块进行观察:
这里有两个重要结构,irb指向事务的最后一条undo记录,即回滚的起点,icl指向事务的第一条undo记录,即回滚的终点。
从前面数据块dump的uba(0x00c03fba.0072.15、0x00c03fba.0072.14)的第三部分可知,事务对应的undo记录为14、15,观察这两条记录:
这里需要注意三点:
-
redo记录中的rci指向的是事务的前一条undo记录;
-
前镜像的内容中只记录了被修改列内容;
-
undo块中存在着一条链表,这个链表见下图:
这就是undo chain的一部分,与事务的混滚操作有关,undo块的irb指向事务undo record的最后一条记录 ,该记录中的rci指向前一个undo record记录,以此类推,最后一个undo record的ric为空,表示事务的起点,也是回滚的终点。
下图是完整的undo chain:
这里大家可以扩展思考一下,oracle的save point是如何实现的,是不是会与undo chain有关?如果修改rci值是不是可以实现回滚部分事务?
下面我们来看一个网上流传比较广的一个图:
从前面我们的实验可以看出,这个图是有歧义的,undo镜像不是块级别的,所以不是一个数据块对应一个undo块,undo镜像其实是列级别的,只有被更改的列才会被记录。
Undo在事务中的工作方式我们就先分析到这。
2 Redo在事务中的作用
2.1 解析redo结构、undo受redo保护的实质、CV对数据块的作用
下面来看一看redo是如何工作的:
接下来dump 405号块进行观察(这里只选取表数据部分)
使用BBED观察DBA+这列的行头信息
下面删除其中的两条数据(这两条数据是位于不同的块中)
Dump上面两个scn之间的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+的数据块)
注意,这里nrow显示还有两行数据,但是删除行的数据没有在dump中显示;行锁标记也未释放,但是事务已经提交了,这就是Oracle的快速提交、和延迟块清除机制,只是保证修改undo段头事务表信息,块头和行头信息不一定进行修改。
那么delete到底发生了什么?下面用bbed进行观察:
发现被删除的数据依然在块中,只是行头标记被修改,这就是delete的实质。所以在数据被覆盖之前是可以通过修改行头标记恢复被delete的数据的。
还记得我们开始的那句话吗?爱情就像鬼一样,谁都听过,但谁也没见过。通过上面的实验,我们应该看到了一些东西。真爱还是有的!
时间,教会了我们很多东西。有些我们曾经认为根本没有的,后来发现,它确确实实存在着,而有些我们深信不疑的,后来却明白,根本就没有。比如,爱情…
本文来自云栖社区合作伙伴"DBAplus",原文发布时间:2015-11-20