分类: Oracle
2011-03-14 16:16:58
前一段时间解决了一个ORA-1122错误,正好本机的数据库环境由于Windows的自动重起,导致数据库无法打开,出现错误信息也是ORA-1122。
这次出现错误的表空间是UNDO表空间。
上一篇介绍了利用备份进行恢复的方法,这篇尝试重建UNDO表空间的方法。
UNDO表空间的ORA-1122错误解决(一):http://yangtingkun.itpub.net/post/468/455691
由于数据库存在备份,因此可以轻松的对数据库进行恢复,不过难得碰到一个错误的情况,尝试一下是否可以在缺少备份的基础上进行数据库的恢复:
再看一下问题,尝试打开数据库,则会报错:
SQL> CONN /@TEST AS SYSDBA已连接到空闲例程。
SQL> STARTUP MOUNT
ORACLE 例程已经启动。
Total System Global Area 76619308 bytes
Fixed Size 454188 bytes
Variable Size 50331648 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes数据库装载完毕。
SQL> ALTER DATABASE OPEN;
ALTER DATABASE OPEN
*
ERROR 位于第 1 行:
ORA-01122: 数据库文件 2 验证失败
ORA-01110: 数据文件 2: 'F:ORACLEORADATATESTUNDOTBS01.DBF'
ORA-01200: 25600的实际文件大小小于26880块的正确大小
如果没有备份,那么就只能采用其他的方式来进行恢复,如果出现问题的数据文件中的内容不是关键内容的话,也可以考虑使用ALTER DATABASE DATAFILE OFFLINE的方式。
方法可以参考一个类似的案例:一次ORA-1122错误的解决:http://yangtingkun.itpub.net/post/468/455467
不过这里出现问题的是UNDO表空间,如果UNDO表空间中没有要回滚的数据,那么问题比较简单,因为Oracle可以更换UNDO表空间,只需要直接将UNDO表空间的数据文件OFFLINE,启动数据库后,新建一个UNDO表空间,并切换当前的UNDO表空间即可。
但是如果UNDO表空间中记录了要回滚的数据,那么恢复操作就会更复杂了。
尝试OFFLINE出现问题的数据文件:
SQL> ALTER DATABASE DATAFILE 'F:ORACLEORADATATESTUNDOTBS01.DBF' OFFLINE;
数据库已更改。
SQL> ALTER DATABASE OPEN;
数据库已更改。
下面可以为系统创建新的UNDO表空间,并实现切换:
SQL> CREATE UNDO TABLESPACE UNDOTBS2 DATAFILE 'F:ORACLEORADATATESTUNDOTBS02.DBF' SIZE 200M;
表空间已创建。
SQL> SHOW PARAMETER UNDO_TABLESPACE
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_tablespace string UNDOTBS1
SQL> ALTER SYSTEM SET UNDO_TABLESPACE = UNDOTBS2;
系统已更改。
虽然数据库已经启动完成,UNDO表空间也已经切换,但是问题并没有结束,如果尝试删除UNDO表空间UNDOTBS1则会报错:
SQL> DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;
DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES
*
ERROR 位于第 1 行:
ORA-01548: 已找到活动回退段'_SYSSMU1$',终止删除表空间
SQL> SELECT COUNT(*) FROM YANGTK.T;
SELECT COUNT(*) FROM YANGTK.T
*
ERROR 位于第 1 行:
ORA-00376: 此时无法读取文件 2
ORA-01110: 数据文件 2: 'F:ORACLEORADATATESTUNDOTBS01.DBF'
在查询包括需要进行回滚操作的表时,同样会遇到错误。而对于其他没有问题的表,则可以正常访问:
SQL> SELECT COUNT(*) FROM YANGTK.T1;
COUNT(*)
----------
20
现在问题就是前面所提到的,OFFLINE的UNDO表空间中保存着需要进行回滚的记录,而这些记录会导致数据库部分内容还没有最终恢复完成,在此之前受影响的部分对象是无法正常访问的。
SQL> SELECT SEGMENT_NAME, OWNER, TABLESPACE_NAME, STATUS
2 FROM DBA_ROLLBACK_SEGS;
SEGMENT_NAME OWNER TABLESPACE_NAME STATUS
-------------------- ------ -------------------- ----------------
SYSTEM SYS SYSTEM ONLINE
_SYSSMU1$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU2$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU3$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU4$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU5$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU6$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU7$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU8$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU9$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU10$ PUBLIC UNDOTBS1 NEEDS RECOVERY
_SYSSMU11$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU12$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU13$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU14$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU15$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU16$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU17$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU18$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU19$ PUBLIC UNDOTBS2 ONLINE
_SYSSMU20$ PUBLIC UNDOTBS2 ONLINE
已选择21行。
检查系统的回滚段信息,发现UNDOTBS1中的所有回滚段都需要恢复。在没有备份的情况下,只能尝试使用隐含参数将数据库打开,不过这个过程会破坏数据库的一致性,而且可能造成数据库出现逻辑错误。采用下面的方法打开数据库后,应该马上执行EXP备份,重建数据库后,再导入。
下面开始尝试恢复数据库,首先创建PFILE,并关闭数据库:
SQL> CREATE PFILE='F:INITTEST.ORA' FROM SPFILE;
文件已创建。
SQL> SHUTDOWN IMMEDIATE数据库已经关闭。已经卸载数据库。
ORACLE 例程已经关闭。
手工编辑PFILE,修改UNDO_MANAGEMENT为MANUAL,并添加隐含参数_OFFLINE_ROLLBACK_SEGMENTS=(_SYSSMU1$,_SYSSMU2$,……_SYSSMU10$):
*.undo_management='MANUAL'
_offline_rollback_segments=(_SYSSMU1$,_SYSSMU2$,_SYSSMU3$,_SYSSMU4$,_SYSSMU5$,_SYSSMU6$,_SYSSMU7$,_SYSSMU8$,_SYSSMU9$,_SYSSMU10$)
下面重起数据库:
SQL> STARTUP PFILE=F:INITTEST.ORA
ORACLE 例程已经启动。
Total System Global Area 76619308 bytes
Fixed Size 454188 bytes
Variable Size 50331648 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes数据库装载完毕。数据库已经打开。
由于设置了隐含参数,现在可以删除回滚段了:
SQL> DROP ROLLBACK SEGMENT "_SYSSMU1$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU2$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU3$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU4$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU5$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU6$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU7$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU8$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU9$";
回退段已删除。
SQL> DROP ROLLBACK SEGMENT "_SYSSMU10$";
回退段已删除。
下面就可以删除UNDOTBS1表空间了:
SQL> DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;
表空间已丢弃。
表空间删除后,通过重起来去掉加载的隐含参数。至此,恢复操作告一段落:
SQL> SHUTDOWN IMMEDIATE数据库已经关闭。已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。
Total System Global Area 76619308 bytes
Fixed Size 454188 bytes
Variable Size 50331648 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes数据库装载完毕。数据库已经打开。
SQL> SHOW PARAMETER UNDO
NAME TYPE VALUE
------------------------------------ ----------- --------------
undo_management string AUTO
undo_retention integer 10800
undo_suppress_errors boolean FALSE
undo_tablespace string UNDOTBS2
SQL> SELECT COUNT(*) FROM YANGTK.T;
COUNT(*)
----------
1273614
由于数据库处于逻辑损害的状态,而且使用了隐含参数,很可能造成未知的危害,因此这个时候应该对数据库中的全部数据执行导出操作,然后重建数据库,再导入回去。
即使采用了上面的操作,也无法确保数据库中数据的一致性。这是由于采用了上面的恢复方法,导致UNDO表空间中记录的需要回滚的信息丢失,而这部分对应的数据会被认为是已经提交的数据,从而破坏了数据库的事务性。
上一篇文章采用恢复的方法打开数据库后,查询T表的记录是:
SQL> SELECT COUNT(*) FROM YANGTK.T;
COUNT(*)
----------
636807
这里不难看出二者的差别有多大。因此,这种方法的恢复,只是没有备份时不得已而为之。