在alter日志中发现如下错误:
ORA-01578: ORACLE data block corrupted (file # 41, block # 1830)
ORA-01110: data file 41: '/db/oracle10g/oradata/hnst/hnst38.dbf'
同样用dbv也检索到file 41的一个坏块,不过由于之前已经检索过,坏块的具体信息没有全部标示出来,而这个dba 171968294具体的组成成分是哪些也是个人比较疑惑的地方,按理是文件号和块号,不过这里详细的划分方法自己还是很迷惑的。期待大牛解答。
[oracle@hns_hy_hn_xwb_tomora ~]$ dbv file='/db/oracle10g/oradata/hnst/hnst38.dbf' blocksize=8192 logfile='/home/oracle/dbv0626.log'
DBVERIFY: Release 10.2.0.1.0 - Production on Tue Jun 26 13:56:00 2012
Copyright (c) 1982, 2005, Oracle.All rights reserved.
DBV-00200: Block, dba 171968294, already marked corrupted
不过虽然dbv已经标识出具体的坏块,但是并不写入v$database_block_corruption视图中,如果有备份集可以利用oracle 9i推出的数据块的恢复来轻松解决
Backup validate datafile 41;
blockrecover datafile 41 block 1830即可实现轻松的恢复。Backup validate datafile 41会检索坏块然后将坏块的记录写入v$database_block_corruption。
通过block#已经知道这是生产系统中一张重要的table segment,于是考虑用expdp配合oracle的内部事件跳过受损数据来处理(当然有bbed的高手可能会有更好的方法)。
不设置10231 event是无法expdp有corruption block的segment。
[oracle@hns_hy_hn_xwb_tomora ~]$ expdp hnst/hnst dumpfile=0626robots_article.dmp logfile=0626.log parallel=8 directory=back tables=robots_article
Export: Release 10.2.0.1.0 - 64bit Production on Tuesday, 26 June, 2012 13:40:58
Copyright (c) 2003, 2005, Oracle.All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit Production
With the Partitioning, OLAP and Data Mining options
Starting "HNST"."SYS_EXPORT_SCHEMA_01":hnst/******** dumpfile=0626robots_article.dmp logfile=0626.log parallel=8 directory=back tables=robots_article
Estimate in progress using BLOCKS method...
--------skipping
ORA-31693: Table data object "HNST"."ROBOTS_ARTICLE" failed to load/unload and is being skipped due to error:
ORA-29913: error in executing ODCIEXTTABLEPOPULATE callout
ORA-01578: ORACLE data block corrupted (file # 41, block # 1830)
ORA-01110: data file 41: '/db/oracle10g/oradata/hnst/hnst38.dbf'
ORA-39095: Dump file space has been exhausted: Unable to allocate 8192 bytes
Job "HNST"."SYS_EXPORT_SCHEMA_01" stopped due to fatal error at 13:41:44
由于存在corrupted block无法expdp,设置10231 event来跳过坏块可以正常导出.
SQL> alter system set events='10231 trace name context forever,level 10';
System altered.
其实也可以利用rowid来做处理的。
SQL> desc dbms_rowid;
FUNCTION ROWID_BLOCK_NUMBER RETURNS NUMBER
Argument NameTypeIn/Out Default?
------------------------------ ----------------------- ------ --------
ROW_IDROWIDIN
TS_TYPE_INVARCHAR2IN DEFAULT
FUNCTION ROWID_CREATE RETURNS ROWID
Argument NameTypeIn/Out Default?
------------------------------ ----------------------- ------ --------
ROWID_TYPENUMBERIN
OBJECT_NUMBERNUMBERIN
RELATIVE_FNONUMBERIN
BLOCK_NUMBERNUMBERIN
ROW_NUMBERNUMBERIN
这里要利用dbms_rowid.rowid_create这个function来模拟1830 block的各行数据的rowid。
SQL> select /*+rule*/ data_Object_id from dba_objects where object_name='ROBOTS_ARTICLE';
DATA_OBJECT_ID
--------------
51717
SQL> select dbms_rowid.rowid_create(1,51717,41,1830,0) from dual;
DBMS_ROWID.ROWID_CREATE(1,5171
------------------------------
AAAMoFAApAAAAcmAAA
SQL> select dbms_rowid.rowid_create(1,51717,41,1831,0) from dual;
DBMS_ROWID.ROWID_CREATE(1,5171
------------------------------
AAAMoFAApAAAAcnAAA
这里自己说一下rowid的知识,物理扩展的rowid有18位,采用64位编码a~z A~Z 0~9 + /共64位字符表示。
从A开始标号,A表示0然后a表示26、0表示52、+表示62、/表示63,不过自己还没有看见+和/的rowid伪列。
Rowid前6位表示data object number,7到9位表示相对表空间的数据文件号,剩下的6位表示block所在的block_id,最后的三位表示block中的第几条记录。
由于oracle的读取的最小单位是block,那么一旦block中的某个数据行损坏那么整个数据块都无法正常读取。接下来的思路很明确了,利用中间表来保存非1830 block的数据信息。
SQL> insert into robots_article001 select /*+rowed(robots_article)*/* from robots_article where rowid1;
SQL> insert into robots_article001 select /*+rowed(robots_article)*/* from robots_article where rowid>'AAAMoFAApAAAAcnAAA' and 1<>1;
剩下的就是rename表。建立在新建robots_article表时都建立相应的索引,然后再执行插入,毕竟大表上线后create index还是很慢的。
可以运用强大的dbms_repair包来跳过坏块。(dbms_repair功能非常强大,还有很多非常时期的用法)
PROCEDURE SKIP_CORRUPT_BLOCKS
Argument NameTypeIn/Out Default?
------------------------------ ----------------------- ------ --------
SCHEMA_NAMEVARCHAR2IN
OBJECT_NAMEVARCHAR2IN
OBJECT_TYPEBINARY_INTEGERINDEFAULT
FLAGSBINARY_INTEGERINDEFAULT
SQL> execute dbms_repair.skip_corrupt_blocks('HNST','ROBOTS_ARTICLE');
PL/SQL procedure successfully completed.
然后expdp或者ctas来创建表,约束等的。
上述这些坏块的处理方法都是没备份情况下的处理,其实bbed可能更适合处理这些问题,不过由于bbed功能相对来说比较复杂,自己在这方面的研究也不是很深,后续有bbed的案例会积极拿出来分享![@more@]