Oracle数据恢复:SYSTEM回滚段损坏案例一则

前一段时间,接收到一次用户报告,用户因为断电导致了数据库故障.启动时遇到了01555的错误.
通常ORA-01555错误并不可怕,但是如果出现在SYSTEM回滚段上,则问题就严重了,因为SYSTEM回滚段无法Offline,也无法重建.以下是错误的主要信息:
Thu Jul 07 15:18:20 CST 2011
ARC0: LGWR is actively archiving destination LOG_ARCHIVE_DEST_2
Thu Jul 07 15:18:20 CST 2011
ORA-01555 caused by SQL statement below (SQL ID: 7bd391hat42zk, Query Duration=0 sec, SCN: 0x000a.79ed044d):
Thu Jul 07 15:18:20 CST 2011
select /*+ rule */ name,file#,block#,status$,user#,undosqn,xactsqn,scnbas,scnwrp,DECODE(inst#,0,NULL,inst#),ts#,spare1 from undo$ where us#=:1
Thu Jul 07 15:18:20 CST 2011
Errors in file /home/oracle/oracle/admin/EDB01/udump/edb01_ora_1208.trc:
ORA-00604: error occurred at recursive SQL level 1
ORA-01555: snapshot too old: rollback segment number 0 with name “SYSTEM” too small
Error 604 happened during db open, shutting down database
USER: terminating instance due to error 604
Instance terminated by USER, pid = 1208
ORA-1092 signalled during: alter database open…
注意,以下一段SQL非常著名:
select /*+ rule */ name,file#,block#,status$,user#,undosqn,xactsqn,scnbas,scnwrp,DECODE(inst#,0,NULL,inst#),ts#,spare1 from undo$ where us#=:1
这是启动过程中对于undo$的递归读取,获得其中的回滚段信息.如果某个回滚段上存在活动事务,则该事务必须被读取回滚,以便保证事务的一致性.
以下是Oracle 9i的SYSTEM回滚段空间分配,通常这些数据块损坏会非常复杂:
SQL> select segment_name,block_id,blocks from dba_extents where segment_name=’SYSTEM’;
SEGMENT_NAME                     BLOCK_ID     BLOCKS
—————————— ———- ———-
SYSTEM                                  9          8
SYSTEM                                 17          8
SYSTEM                                385          8
SYSTEM                                393          8
SYSTEM                                401          8
SYSTEM                                409          8
对于SYSTEM回滚段,其为Oracle数据库第一个创建的回滚段,主要用于数据库的内部事务或SYS的事务信息记录。如果数据库创建了其他用户的回滚段,则SYSTEM回滚段将近用于UNDO$的信息记录,这也是为什么在出现问题时,我们看到的是在undo$读取时抛出的异常。
在sql.bsq文件中,记录了数据库创建第一个步骤中的SYSTEM回滚段信息:
create tablespace SYSTEM datafile “D_DBFN”
  “D_DSTG” online
/
create rollback segment SYSTEM tablespace SYSTEM
  storage (initial 50K next 50K)
/
系统回滚段的作用如下:
When a database is first created using the CREATE DATABASE command, only a single rollback segment is created.
This is the system rollback segment and it is created in the system tablespace.
The system rollback segment has one basic difference from any other rollback segment, including any other rollback segments that are created in the system tablespace.
This difference is that the system rollback segment can only be used for transactions that occur on objects inside the system tablespace.
This is done because the main purpose of the system rollback segment is to handle rollback for DDL transactions – that is transactions against the data dictionary tables themselves.  Making the system rollback usable only for the system tablespace was simply an easy way to enforce that.
It is possible for the system rollback segment to be used for non-data dictionary tables, but only if those tables are created inside the system tablespace (which is very bad development practice).
Steve对此的重要注解
When other rollback segments are available, the SYSTEM rollback segment is only used for the changes to UNDO$ associated with bringing other rollback segments online, or taking them offline.
至于SYSTEM回滚段损坏,你最好有备份,否则就只能通过BBED去修改相关的数据块。我们处理过类似大量案例。如果你正好遇到类似问题,那么请直接联系我们.

某客户一套12TB数据库的恢复过程

某客户要数据库损坏,通过备份进行恢复时,遇到来难题。本来是一件很简单的事情,restore文件,然后recover归档,恢复到某个点,然后open resetlogs 打开数据库,但是居然报错,ora-600 [4097],很常见的一个错误,不过比较怪异的是,这里并没有直接提示是哪个回滚段有问题,如下是trace内容:

其实我们可以尝试reset incarnation,然后再去restore归档,然后recover,想想麻烦,反正是测试,所以继续搞下去。

首先利用10046 event 来跟踪一下,发现如下sql报错:

实际上因为oracle 在open的时候会去判断回滚端上是否存在事物,如果存在,那么就会进行update,如果进行update那么也就说明正在open的时候需要更新回滚端的信息。这里尝试使用参数将上述几个回滚端屏蔽掉,发现仍然无法open,再次寻找10046 trace,发现原来是另外一个回滚段可能有问题,如下:

果断再次屏蔽,然后尝试open resetlogs,发热仍然报错,原来这个回滚端用无法直接offline,隐含参数不好用,因此直接bbed 修改状态吧,如下:

修改之后成功open 数据库。

虽然打开了,但是奇葩的还在后面,当我shutdown 再次启动,居然无法启动了。 报错ora-01555,比较经典的错误。

比较郁闷的是system 回滚段。很明显这也跟scn有关系,aix平台,尝试oradebug 修改scn,发现比较费劲。

最后果断bbed 再次修改block(仍然通过10046 trace 寻找相关的block).

最后再次open,发现一切顺利。

经过努力,我们可以发现成功打开了数据库,经检查也没有其他问题。

某大学的Oracle数据库恢复案例

某客户的数据库出现崩溃,无法正常启动,经过我的远程紧急救援恢复之后,恢复正常,如下是简单的处理过程,供参考!

在open数据库时,发现无法打开,报错如下:

对于上述错误,其实是比较常见的,大致上可以理解为Oracle在open 时需要进行一致性读的处理,却发现回滚段内容已经被覆盖,进而报错ora-01555,导致无法open。我们也可以发现,报错的SQL预计是Oracle 递归SQL,这是数据库在open时必须执行的SQL,很明显,该SQL无法执行成功,那么也就导致数据库无法正常打开。

处理思路很简单,首先我们要做的事情是通过10046 trace跟踪确认数据库在执行该SQL时访问了那些block,进而报错的?

通过oracle 10046 trace得到如下的内容:

根据我们常见的处理思路,将上述访问的block中的事务状态改成8000之后,发现仍然报错。我们仔细来对比下block中的scn与报错的scn信息,发现了其中的关系,如下:

将上述的scn bas值转换为10 进制后为:489416426,我们再来查询下数据库文件头的scn:

我们不难发现,报错的block中的scn比数据文件头的scn要大,其次也比前面报错的的scn:1d2be1e6 (转换后为 489415142)要大一些。这说明什么?

当数据库处于running的情况之下,Oracle 不知道下一个时间点事务什么时间结束,因此也不知道下一个时间点的scn是多少,所以其对应的scn 往往要比当前的大一些。当数据库crash后,加上undo损坏,那么很容易出现这样的情况。

所以,我们这要做的事情,很简单,将上述scn 修改得比报错的scn小一些(或者等于),则可以解决该错误。

修改之后,再次启动数据库,发现报错发生了变化,查看此时的alert log,发现信息如下:

很明显,这是scn的问题,要处理也很简单,通过推进scn即可解决掉。通过推进scn之后,发现打开数据库时,还是报错了,但是错误再一次发生了改变:

这次过程处理起来就很简单了,通过屏蔽undo就可以很容易解决掉。其次在后续的恢复过程中,还遇到了如下的一些错误:

这部分错误处理起来都相对简单的多。【4097】也是回滚段的问题,在处理undo时,可以一并处理之。我博客之前就写了该错误的处理案例,这里不再累述。这种恢复场景,最后打开数据库后一般还会有如下的错误:

最后这个错误处理起来十分简单,通过重建index即可解决上述错误,对于大量的 日志,建议直接grep,然后重建相关index即可。

最后通过mos的脚本来check 数据字典是否存在异常,这样就可以确保数据库起码可以正常运行。如下是检测结果:

我们可以发现,至少通过Oracle mos的脚本检查之后,没有数据字典有问题。

对于这样的复杂数据恢复,建议联系 云和恩墨 获取专业技术支持!

某客户一套15TB的数据库恢复小记

该客户数据库在春节之前就出现故障,后面经过多人尝试恢复后,均为打开数据库;数据库在open时报如下错误:

该错误其实很场景,也恢复过太多这种情况了,这里不再过多描述。不过这里让我感觉很诧异的是该SQL的Query Duration 太大了。
根据经验,这种情况下可以直接推进SCN。可是当我们进行如下操作,发现不起作用:

alter session set events ‘10015 trace name adjust_scn level 13740’;

进一步通过10046 trace跟踪发现该sql访问了如下几个block:

通过分别dump上述block,我们发现file 1 block 122 有点小问题,如下:

通过脚本将该block copy到文件系统,bbed进行修改之后,再copy回asm diskgroup。
接着再次进行scn的推进,可以很顺利打开数据库。

这里需要注意的是,虽然打开了数据库,但是后面还有很多善后处理工作,比如我们dbv发现undo有坏块,那么就需要重建undo;同时检查alert log是否伴随其他的错误。

其次,对于强制open的数据库,我们建议通过mos脚本检查下数据字典是否存在异常;如果数据字典有明显异常,那么通常是需要通过逻辑导出来重建数据库的;否则一般不需要重建库。

对于是否需要重建库,我认为没有定论,安全起见是通常是建议重建数据库;或者数据库很小的时候也可以考虑重建;否则通过检查数据库告警,或者数据库运行一段时间没有其他异常,那么完全可以不重建数据库。