2012年8月23日 七夕节 本来要陪老婆过节呢,接到了一个数据库故障处理的任务
接到客户任务为晚上7点,吃过饭回来时间为8点整。数据库:oracle 9.2.0.0.0,平台:windows server 2003,数据库未归档,也没有备份.
据客户描述,前几天服务器数据库突然垮掉,机器蓝屏了,随后他们将机器强免打开,将oracle 数据库文件全部拷贝出来,放到了
另外的两台机器A和B,A和B机器的文件路径及实例配置和以前那台机器一模一样。首先我问了那个哥们数据库还有没有备份,他说有
然后我就开始干活了我连上客户的A机器,发现数据库已经处于MOUNT状态就是打不开,当用启动数据库时候就报错,如下:
SQL> startup
ORACLE instance started.
Total System Global Area 167772160 bytes
Fixed Size 1218316 bytes
Variable Size 71305460 bytes
Database Buffers 92274688 bytes
Redo Buffers 2973696 bytes
Database mounted.
ORA-01122: database file 1 failed verification check
ORA-01110: data file 1: '/free/oracle/oradata/orcl/system01.dbf'
ORA-01207: file is more recent than control file - old control file
出现了ORA-01207错误:
随后我就在MOUNT状态新建CONTROL文件:
2012年08月23日 19:52:30
SQL> alter database backup controlfile to trace 'e:\createctl.sql';
Database altered.
SQL>
编辑文件e:\createctl.sql
STARTUP NOMOUNT
CREATE CONTROLFILE REUSE DATABASE "XXX" RESETLOGS NOARCHIVELOG
MAXLOGFILES 16
MAXLOGMEMBERS 3
MAXDATAFILES 100
MAXINSTANCES 8
MAXLOGHISTORY 2336
LOGFILE
GROUP 1 'e:\.....\redo01.log' SIZE 50M,
GROUP 2 'e:\.....\redo02.log' SIZE 50M,
GROUP 3 'e:\.....\redo03.log' SIZE 50M
-- STANDBY LOGFILE
DATAFILE
'e:\.....dbf'
.......
CHARACTER SET ZHS16CGB231280
;
Oracle控制文件已创建。
SQL> alter database open resetlogs;
到此步骤,又报错了,说是system表空间需要恢复,天哪,没有备份怎么恢复,recover database了几次还是没有成功,这里不知道
网友遇到过没有,如果有,请指教,或许添加什么什么隐含参数可以打开数据库的....
2012年08月23日 21:07:31
刚好这时候客户让我看了B机器说是也报错数据读取不了,但是数据库是打开的,如下错误:
ora-00376:此时无法读取文件2
ora-01110:数据文件2:'E:\oracle\.....\undotbs01.dbf'
我一看就知道是undo除了问题,脸上去重新在oem里点了”方案“,错误又出现了,然后
SQL> show parameter undo
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS1
SQL>
重建UNDO表空间:
SQL> col name format a45
SQL> select name from v$datafile;
NAME
---------------------------------------------
e:\oracle\......\XXXX\system01.dbf
e:\oracle\......\XXXX\undotbs01.dbf
e:\oracle\......\XXXX\sysaux01.dbf
e:\oracle\......\XXXX\users01.dbf
e:\oracle\......\XXXX\rrac_basdata
e:\oracle\......\XXXX\rrac_basdata1
e:\oracle\......\XXXX\rrac_etcdata
e:\oracle\......\XXXX\rrac_etcdata1
e:\oracle\......\XXXX\rrac_etcdata2
e:\oracle\......\XXXX\rrac_etcdata3
e:\oracle\......\XXXX\rrac_etcdata4
SQL> CREATE UNDO TABLESPACE undotbs2
2 DATAFILE 'e:\oracle\......\XXXX\undotbs02.dbf'
3 SIZE 50M autoextend on next 10m MAXSIZE UNLIMITED;
Tablespace created.
SQL> ALTER SYSTEM SET undo_tablespace='UNDOTBS2' ;
System altered.
SQL> show parameter undo
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
undo_management string AUTO
undo_retention integer 900
undo_tablespace string UNDOTBS2
SQL>
等再点方案时候还报错,想删掉之前的UNDO也删不掉
虽然数据库已经启动完成,UNDO表空间也已经切换,但是问题并没有结束,如果尝试删除UNDO表空间UNDOTBS1则会报错:
SQL> DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES;
DROP TABLESPACE UNDOTBS1 INCLUDING CONTENTS AND DATAFILES
*
ERROR 位于第 1 行:
ORA-01548: 已找到活动回退段'_SYSSMU1$',终止删除表空间
现在问题就是前面所提到的,之前拷贝过来的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行。
下面开始尝试恢复数据库,首先创建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$)
PFILE文件:INITXXXX.ORA内容如下:
*._allow_resetlogs_corruption=TRUE
*.aq_tm_processes=1
*.background_dump_dest='E:\Oracle\admin\ysgszw\bdump'
*.compatible='9.2.0.0.0'
*.control_files='e:\oracle\oradata\xxxx\control01.ctl'
*.core_dump_dest='E:\Oracle\admin\xxxx\cdump'
*.db_block_size=8192
*.db_cache_size=25165824
*.db_domain=''
*.db_file_multiblock_read_count=16
*.db_name='xxxx'
*.dispatchers='(PROTOCOL=TCP) (SERVICE=xxxxXDB)'
*.fast_start_mttr_target=300
*.hash_join_enabled=TRUE
*.instance_name='xxxx'
*.java_pool_size=33554432
*.job_queue_processes=10
*.large_pool_size=8388608
*.open_cursors=300
*.pga_aggregate_target=25165824
*.processes=300
*.query_rewrite_enabled='FALSE'
*.remote_login_passwordfile='EXCLUSIVE'
*.sessions=300
*.shared_pool_size=50331648
*.sort_area_size=524288
*.star_transformation_enabled='FALSE'
*.timed_statistics=TRUE
*.undo_management='MANUAL'
*.undo_retention=10800
*.undo_tablespace='UNDOTBS2'
*.user_dump_dest='E:\Oracle\admin\xxxx\udump'
_offline_rollback_segments=(_SYSSMU1$,_SYSSMU2$,_SYSSMU3$,_SYSSMU4$,_SYSSMU5$,_SYSSMU6$,_SYSSMU7$,_SYSSMU8$,_SYSSMU9$,_SYSSMU10$)
2012年08月23日 23:40:31
下面重起数据库:
SQL> STARTUP PFILE=E:INITXXXX.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
2012年08月24日 2:40:31
数据库启动之后不再报错了,但是临时表空间报错,访问表说没有临时表空间,果断的新建:
SQL> CREATE TEMPORARY TABLESPACE temp1
2 tempfile '/oracle/oradata/DBETCTEST/temp02.dbf'
3 SIZE 50M autoextend on next 10m MAXSIZE UNLIMITED;
Tablespace created.
SQL> alter database default temporary tablespace temp1;
Database altered.
SQL> drop tablespace temp including contents and datafiles;
Tablespace dropped.
SQL>
至此再访问数据库中的表不会再报缺少临时表空间的错误了。
按照规律,通过隐含参数和删除回滚段强制打开了数据库,我们没法保证数据库的一致性和完整性,对数据库已造成未知的危害,
这种情况下我们需要将所有用户数据导出,在新建库,将数据库导入新的数据库中,下面导出:
但是又遇到了错误,导出用户报错,但是导出单个表不报错
exp mm/mm file=E:\mm.dmp wner=mm
.....
ora-00600: [12700][18][.....][10][]
报如上错误,于是怀疑数据库中有对象出现坏块,因为当时是突然机器出现蓝屏,硬件故障,磁盘出问题。
在网上查了查,参考pub上chensq的案例,确定出错的obj#为18
SQL> select name from obj$ where obj#=18 ;
NAME
------------------------------
OBJ$
这样,问题就出在OBJ$上了。
第一步,看看是不是表损坏
SQL> analyze table obj$ validate structure ;
表已分析。
对表的分析没有报错,说明损坏不在表上。
再对索引进行分析:
SQL> analyze table obj$ validate structure cascade ;
analyze table obj$ validate structure cascade
*
ERROR 位于第 1 行:
ORA-01499: 表/索引交叉引用失败 - 请参阅跟踪文件
是索引的问题!
那么这个索引又怎么确定呢?
首先,得找到该表存在哪些索引:
SQL> select INDEX_NAME from dba_indexes where table_name='OBJ$' ;
INDEX_NAME
------------------------------
I_OBJ3
I_OBJ1
I_OBJ2
SQL> l
1 SELECT --+INDEX( OBJ$ I_OBJ3)
2* OBJ# FROM OBJ$
OBJ#
----------
7146
7149
7156
已选择6203行。
SQL> l
1 SELECT --+INDEX( OBJ$ I_OBJ1)
2* OBJ# FROM OBJ$
OBJ#
----------
7146
7149
7156
已选择6803行。
SQL> l
1 SELECT --+INDEX( OBJ$ I_OBJ2)
2* OBJ# FROM OBJ$
OBJ#
----------
1711
407
417
414
409
411
ERROR:
ORA-00600: 内部错误代码,参数: [12700], [18], [46464646], [5], [], [], [], []
已选择1288行。
到这里已经可以看出,是I_OBJ2坏了。
重建索引试试:
SQL> alter index I_OBJ2 rebuild online ;
alter index I_OBJ2 rebuild online
*
ERROR 位于第 1 行:
ORA-00701: 无法改变热启动数据库所需的对象
根本不可以!
删除试试呢?
SQL> drop index i_obj2 ;
drop index i_obj2
*
ERROR 位于第 1 行:
ORA-00701: 无法改变热启动数据库所需的对象
不行!现在我决定不使用它,总可以了吧?
SQL> alter index I_OBJ2 unusable ;
alter index I_OBJ2 unusable
*
ERROR 位于第 1 行:
ORA-00701: 无法改变热启动数据库所需的对象
唉,还是不行!
2012年08月24日 3:10:31
检查下数据坏块:
C:\>dbv file=f:\600-12700\system01.dbf blocksize=4096
DBVERIFY: Release 9.2.0.1.0 - Production on 星期六 5月 28 18:07:04 2005
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
DBVERIFY - 验证正在开始 : FILE = f:\600-12700\system01.dbf
DBVERIFY - 验证完成
检查的页总数 :61440
处理的页总数(数据):39665
失败的页总数(数据):0
处理的页总数(索引):4380
失败的页总数(索引):0
处理的页总数(其它):1546
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数 :15849
标记为损坏的总页数:0
汇入的页总数 :0
居然为0!说明没有坏块
猜测:在导出过程中oracle要读取系统的表或视图,而在读取时候使用了这个索引,那
我们在导出时候能不能禁止它使用索引呢,不让他使用无非是查询导出速度慢一些,性能
有些影响,对功能不影响就可以了,只要能把数据导出就万事大吉了,哈哈!
在udump下找到导出报错后生成的trace文件
ksedmp: internal or fatal error
ORA-00600: 内部错误代码,参数: [12700], [18], [46464646], [5], [], [], [], [php]
Current SQL statement for this session:
select object_name, object_type
from sys.user_objects o
where o.object_type in (:"SYS_B_0", :"SYS_B_1", :"SYS_B_2",:"SYS_B_3", :"SYS_B_4", :"SYS_B_5", :"SYS_B_6")
这个就是引起12700错误的那个SQL了!先看一下执行计划:
[php]
explain plan for
select object_name, object_type
from sys.user_objects o
where o.object_type in (:"SYS_B_0", :"SYS_B_1", :"SYS_B_2",:"SYS_B_3", :"SYS_B_4", :"SYS_B_5", :"SYS_B_6")
select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
| 1 | VIEW | USER_OBJECTS | | | |
| 2 | UNION-ALL | | | | |
|* 3 | FILTER | | | | |
|* 4 | TABLE ACCESS BY INDEX ROWID| OBJ$ | | | |
|* 5 | INDEX RANGE SCAN | I_OBJ2 | | | |
|* 6 | TABLE ACCESS BY INDEX ROWID| IND$ | | | |
|* 7 | INDEX UNIQUE SCAN | I_IND1 | | | |
|* 8 | FILTER | | | | |
|* 9 | INDEX RANGE SCAN | I_LINK1 | | | |
--------------------------------------------------------------------------------
果然要用到I_OBJ2索引!那么我们就从这个视图下手:
create or replace view USER_OBJECTS
(OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE,
CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED,
SECONDARY)
as
select --+ NO_INDEX(O i_obj2)
o.name, o.subname, o.obj#, o.dataobj#,
decode(o.type#, 0, 'NEXT OBJECT', 1, 'INDEX', 2, 'TABLE', 3, 'CLUSTER',
4, 'VIEW', 5, 'SYNONYM', 6, 'SEQUENCE',
7, 'PROCEDURE', 8, 'FUNCTION', 9, 'PACKAGE',
11, 'PACKAGE BODY', 12, 'TRIGGER',
13, 'TYPE', 14, 'TYPE BODY',
19, 'TABLE PARTITION', 20, 'INDEX PARTITION', 21, 'LOB',
22, 'LIBRARY', 23, 'DIRECTORY', 24, 'QUEUE',
28, 'JAVA SOURCE', 29, 'JAVA CLASS', 30, 'JAVA RESOURCE',
32, 'INDEXTYPE', 33, 'OPERATOR',
34, 'TABLE SUBPARTITION', 35, 'INDEX SUBPARTITION',
40, 'LOB PARTITION', 41, 'LOB SUBPARTITION',
42, 'MATERIALIZED VIEW',
43, 'DIMENSION',
44, 'CONTEXT', 46, 'RULE SET', 47, 'RESOURCE PLAN',
48, 'CONSUMER GROUP',
51, 'SUBSCRIPTION', 52, 'LOCATION',
55, 'XML SCHEMA', 56, 'JAVA DATA',
57, 'SECURITY PROFILE', 59, 'RULE',
62, 'EVALUATION CONTEXT',
'UNDEFINED'),
o.ctime, o.mtime,
to_char(o.stime, 'YYYY-MM-DD:HH24:MI:SS'),
decode(o.status, 0, 'N/A', 1, 'VALID', 'INVALID'),
decode(bitand(o.flags, 2), 0, 'N', 2, 'Y', 'N'),
decode(bitand(o.flags, 4), 0, 'N', 4, 'Y', 'N'),
decode(bitand(o.flags, 16), 0, 'N', 16, 'Y', 'N')
from sys.obj$ o
where o.owner# = userenv('SCHEMAID')
and o.linkname is null
and (o.type# not in (1 /* INDEX - handled below */,
10 /* NON-EXISTENT */)
or
(o.type# = 1 and 1 = (select 1
from sys.ind$ i
where i.obj# = o.obj#
and i.type# in (1, 2, 3, 4, 6, 7, 9))))
and o.name != '_NEXT_OBJECT'
and o.name != '_default_auditing_options_'
union all
select l.name, NULL, to_number(null), to_number(null),
'DATABASE LINK',
l.ctime, to_date(null), NULL, 'VALID', 'N', 'N', 'N'
from sys.link$ l
where l.owner# = userenv('SCHEMAID')
..[/php]
在这个视图中,用hint( --+ NO_INDEX(O i_obj2))把索引禁用了,一切OK!
在这里再说一句,在查找过程中一个视图被另一个视图调用,直到要找到最底层
的表sys.obj$才能在那个创建视图的语句中添加禁用hint,要不不会起作用的
随后又导出,又报错了,且到trace文件里看只有一个是访问视图的sql,而且每次导出
在 exp之后导出的内容都比上次多些,这样处理下去,直到所有的用户内容被导出就好了
,在这里总共处理了有十几个视图(用toad工具control+鼠标左键很快能找到),最后导出其它
用户的数据也没再报错
2012年08月24日 5:00:31
主要是导出数据花费时间,
一:禁用了索引速度变慢
二:用每次导出的方法试着触发他报错,然后再去处理错误
2012年08月24日 5:30:31
下来之后我叮嘱客户重建一个新库和几个用户将导出的数据再导入,使用新的数据库,且将数据库开
归档和备份
2012年08月24日 6:00:00
唉,忙了一夜,可真累啊,倒下打了30分钟的盹 7点上班去!
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16400082/viewspace-742018/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/16400082/viewspace-742018/