坏块检查
可以通过RMAN来检查数据文件是否存在坏块:
针对整个数据库
Rman> backup validate check logical database ;
针对特定的数据文件
Rman> backup validate check logical datafile <fileno> ;
完成以后查询视图
SQL>Select * from v$database_block_corruption ;
或者可以通过dbv工具检查坏块:
$ dbv userid={system/password} file={full path filename} logfile={output filename}
二、检查坏块是否属于某个对象
针对少量坏块
查询dba_extents并复核坏块不属于任何对象:
SQL> select segment_name, segment_type, ownerfrom dba_extentswhere file_id = <Absolute file number>and <corrupted block number> between block_idand block_id + blocks -1;
如果坏块不属于任何对象,复核一下这个块是否存在于
dbafreespace:
SQL> Select *from dba_free_spacewhere file_id= <Absolute file number>and <corrupted block number> between block_idand block_id + blocks -1;
针对大量坏块
通过以下查询语句句来判断块是否为空块或者被使用:
set lines 200 pages 10000col segment_name format a30SELECT e.owner, e.segment_type, e.segment_name, e.partition_name, c.file#,greatest(e.block_id, c.block#) corr_start_block#,least(e.block_id+e.blocks-1, c.block#+c.blocks-1) corr_end_block#,least(e.block_id+e.blocks-1, c.block#+c.blocks-1)- greatest(e.block_id, c.block#) + 1 blocks_corrupted,null descriptionFROM dba_extents e, v$database_block_corruption cWHERE e.file_id = c.file#AND e.block_id <= c.block# + c.blocks - 1AND e.block_id + e.blocks - 1 >= c.block#UNIONSELECT s.owner, s.segment_type, s.segment_name, s.partition_name, c.file#,header_block corr_start_block#,header_block corr_end_block#,1 blocks_corrupted,'Segment Header' descriptionFROM dba_segments s, v$database_block_corruption cWHERE s.header_file = c.file#AND s.header_block between c.block# and c.block# + c.blocks - 1UNIONSELECT null owner, null segment_type, null segment_name, null partition_name, c.file#,greatest(f.block_id, c.block#) corr_start_block#,least(f.block_id+f.blocks-1, c.block#+c.blocks-1) corr_end_block#,least(f.block_id+f.blocks-1, c.block#+c.blocks-1)- greatest(f.block_id, c.block#) + 1 blocks_corrupted,'Free Block' descriptionFROM dba_free_space f, v$database_block_corruption cWHERE f.file_id = c.file#AND f.block_id <= c.block# + c.blocks - 1AND f.block_id + f.blocks - 1 >= c.block#ORDER BY file#, corr_start_block#;
三、数据块修复
修复空坏块
如果rman在读到坏块的时候不会报错,则可以通过rman来修复坏块
对包含坏块数据文件进行一次rman备份来确定该方法适用:
RMAN> backup check logical datafile 7 format '/oradata/backup/%U' tag 'CORRUPT_BLK_FILE_BKP';Starting backup at 21-MAY-12using channel ORA_DISK_1channel ORA_DISK_1: starting full datafile backup setchannel ORA_DISK_1: specifying datafile(s) in backup setinput datafile file number=00007 name=/oradata/ora11gR2/demo01.dbfchannel ORA_DISK_1: starting piece 1 at 21-MAY-12channel ORA_DISK_1: finished piece 1 at 21-MAY-12piece handle=/oradata/backup/1jnbhl5c_1_1 tag=CORRUPT_BLK_FILE_BKP comment=NONEchannel ORA_DISK_1: backup set complete, elapsed time: 00:00:01Finished backup at 21-MAY-12
确保备份空间充足,可以使用format子句指定备份的位置。
另外,即使备份成功,也要检查确认备份中不存坏块:
SQL> select BP.HANDLE, BP.COMPLETION_TIME, BC.FILE#, BC.BLOCK#, BC.BLOCKS, BC.MARKED_CORRUPT, BC.CORRUPTION_TYPE 2from V$BACKUP_PIECE BP, V$BACKUP_CORRUPTION BC 3where BP.SET_COUNT = BC.SET_COUNTand 4 BP.SET_STAMP = BC.SET_STAMPand 5 BP.TAG = 'CORRUPT_BLK_FILE_BKP';no rows selected
如果该查询有返回结果,则无法使用rman修复空坏块。
如果没有返回结果,表示rman的优化算法跳过了这些没有被使用的块,则当使用这个备份片恢复数据文件时,这些块会被格式化,可以通过以下步骤修复坏块:
将数据文件还原到别的位置:
RMAN> run {2> set newname for datafile 7 to '/oradata/ora11gR2/demo01_RESTORED.dbf';3> restore datafile 7 from tag 'CORRUPT_BLK_FILE_BKP';4> }executing command: SET NEWNAMEStarting restore at 21-MAY-12using channel ORA_DISK_1channel ORA_DISK_1: starting datafile backup set restorechannel ORA_DISK_1: specifying datafile(s) to restore from backup setchannel ORA_DISK_1: restoring datafile 00007 to oradata/ora11gR2/demo01_RESTORED.dbfchannel ORA_DISK_1: reading from backup piece oradata/backup/1jnbhl5c_1_1channel ORA_DISK_1: piece handle=/oradata/backup/1jnbhl5c_1_1 tag=CORRUPT_BLK_FILE_BKPchannel ORA_DISK_1: restored backup piece 1channel ORA_DISK_1: restore complete, elapsed time: 00:00:03Finished restore at 21-MAY-12
使用dbv来验证还原出的文件没有坏块:
$ dbv file=/oradata/ora11gR2/demo01_RESTORED.dbf blocksize=8192DBVERIFY: Release 11.2.0.3.0 - Production on Mon May 21 12:27:21 2012Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.DBVERIFY - Verification starting : FILE = oradata/ora11gR2/demo01_RESTORED.dbfDBVERIFY - Verification completeTotal Pages Examined : 12800Total Pages Processed (Data) : 0Total Pages Failing (Data) : 0Total Pages Processed (Index): 0Total Pages Failing (Index): 0Total Pages Processed (Other): 12799Total Pages Processed (Seg) : 0Total Pages Failing (Seg) : 0Total Pages Empty : 1Total Pages Marked Corrupt : 0Total Pages Influx : 0Total Pages Encrypted : 0Highest block SCN : 775154 (0.775154)
使用BLOCKRECOVER命令来修复坏块
这个命令将使用还原出的数据文件中的格式化过的空块来修复空坏块:
RMAN> blockrecover datafile 7 block 150 FROM DATAFILECOPY;Starting recover at 21-MAY-12allocated channel: ORA_DISK_1channel ORA_DISK_1: SID=22 device type=DISKchannel ORA_DISK_1: restoring block(s) from datafile copy oradata/ora11gR2/demo01_RESTORED.dbfstarting media recoverymedia recovery complete, elapsed time: 00:00:01Finished recover at 21-MAY-12
运行dbv命令来验证原先的数据文件已经没有坏块:
[oracle@vmOraLinux6 ~]$ dbv file=/oradata/ora11gR2/demo01.dbf blocksize=8192DBVERIFY: Release 11.2.0.3.0 - Production on Mon May 21 12:30:15 2012Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.DBVERIFY - Verification starting : FILE = oradata/ora11gR2/demo01.dbfDBVERIFY - Verification completeTotal Pages Examined : 12800Total Pages Processed (Data) : 356Total Pages Failing (Data) : 0Total Pages Processed (Index): 0Total Pages Failing (Index): 0Total Pages Processed (Other): 152Total Pages Processed (Seg) : 0Total Pages Failing (Seg) : 0Total Pages Empty : 12292Total Pages Marked Corrupt : 0Total Pages Influx : 0Total Pages Encrypted : 0Highest block SCN : 775154 (0.775154)
另外,也可以使用rman来验证:
RMAN> backup validate check logical datafile 7;Starting backup at 21-MAY-12using target database control file instead of recovery catalogallocated channel: ORA_DISK_1channel ORA_DISK_1: SID=22 device type=DISKchannel ORA_DISK_1: starting full datafile backup setchannel ORA_DISK_1: specifying datafile(s) in backup setinput datafile file number=00007 name=/oradata/ora11gR2/demo01.dbfchannel ORA_DISK_1: backup set complete, elapsed time: 00:00:03List of Datafiles=================File Status Marked Corrupt Empty Blocks Blocks Examined High SCN---- ------ -------------- ------------ --------------- ----------7 OK 0 12292 12801 775154File Name: /oradata/ora11gR2/demo01.dbfBlock Type Blocks Failing Blocks Processed---------- -------------- ----------------Data 0 356Index 0 0Other 0 152Finished backup at 21-MAY-12
如果无法使用rman修复,则可以使用如下方法修复
使用sys或system用户创建一张表,可以使用nologging选项避免生成日志,使用pctfree 99来加速格式化:
SQL> create table s( n number,c varchar2(4000)) nologging tablespace <tablespace name having the corrupt block> pctfree 99;
验证这个表被创建在了正确的表空间:
SQL> select segment_name,tablespace_namefrom user_segmentswhere segment_name='S' ;
deferred_segment_creation=true,
SQL>select table_name,tablespace_namefrom user_tableswhere table_name='S' ;
创建⼀个触发器,当坏块被重用时会抛出⼀个异常:
1、显示输入blocknumber时,输入坏块号,
2、显示输入filenumber时,输入坏块所在数据文件的文件号 (rfile# value from v$datafile)
CREATE OR REPLACE TRIGGER corrupt_triggerAFTER INSERT ON sREFERENCING OLD AS p_old NEW AS new_pFOR EACH ROWDECLAREcorrupt EXCEPTION;BEGINIF (dbms_rowid.rowid_block_number(:new_p.rowid)=&blocknumber)and (dbms_rowid.rowid_relative_fno(:new_p.rowid)=&filenumber) THENRAISE corrupt;END IF;EXCEPTIONWHEN corrupt THENRAISE_APPLICATION_ERROR(-20000, 'Corrupt block has been formatted');END;/
通过dba_free_space查询空坏块extent的大小:
SQL> Select BYTESfrom dba_free_spacewhere file_id=<file no>and <corrupt block no> between block_idand block_id + blocks -1;BYTES----------------65536
这里是64k,则分配一个64k的extent:
SQL> alter table sallocate extent (DATAFILE 'E:\xxxx\test.ORA' SIZE 64K);
若为64k的n倍,则使用这个循环语句来分配extent:
BEGINfor i in 1..1000000 loopEXECUTE IMMEDIATE 'alter table s allocate extent (DATAFILE '||'''E:\xxxx\test.ORA''' ||'SIZE 64K) ';end loop;end ;/
不断的分配,直到坏块被包含在s表中。可以通过以下查询来验证:
SQL> select segment_name, segment_type, ownerfrom dba_extentswhere file_id = <Absolute file number>and <corrupt block number> between block_idand block_id + blocks -1 ;
注意以下几点:
1、如果表空间是ASSM的,则可能需要多次执行分配空间的命令或使用多张表;
2、建议将autoextend设置为off;
3、如果数据库版本为10.2.0.4/11.1.0.7,在ASSM的表空房间手工分配空间,会触发Bug 6647480
向s表中插入数据,当有数据被插入到坏块时,触发器会被触发:
BeginFOR i IN 1..1000000000 loopfor j IN 1..1000 loopInsert into s VALUES(i,'x');end loop;commit;END LOOP;END;
使用rman来验证坏块已经被修复:略
删除刚刚使用的表:
SQL> DROP TABLE s ;
切换几次日志,并做一次checkpoint:
SQL>Alter system switch logfile ; --> 执⾏多次SQL>Alter system checkpoint ;
最后,删除触发器器:
SQL> DROP trigger corrupt_trigger ;
四、修复坏数据块
坏块属于索引
如果坏块属于索引,则删除并重新创建索引即可:
SQL> DROP index <index_name> ;SQL> CREATE index <index_name> ON ......;
坏块属于表
当查询全表时不会报错,则可以通过以下方法修复坏块:
1、shrink这张表;
2、在同⼀个表空间move这张表;
3、将这张表rename,然后CTAS这张表(create table as select)
如果查询全表时报错,则需要使⽤用DBMS_REPAIR包来修复,修复用的脚本如下:
REM Create the repair table in a given tablespace:BEGIN DBMS_REPAIR.ADMIN_TABLES (TABLE_NAME => 'REPAIR_TABLE',TABLE_TYPE => dbms_repair.repair_table,ACTION => dbms_repair.create_action,TABLESPACE => '&tablespace_name');END;/REM Identify corrupted blocks for schema.object (it also can be done at partition level with parameter PARTITION_NAME):set serveroutput onDECLARE num_corrupt INT;BEGINnum_corrupt := 0;DBMS_REPAIR.CHECK_OBJECT (SCHEMA_NAME => '&schema_name',OBJECT_NAME => '&object_name',REPAIR_TABLE_NAME => 'REPAIR_TABLE',corrupt_count => num_corrupt);DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt));END;/REM Optionally display any corrupted block identified by check_object:select BLOCK_ID, CORRUPT_TYPE, CORRUPT_DESCRIPTIONfrom REPAIR_TABLE;REM Mark the identified blocks as corrupted ( Soft Corrupt - reference Note 1496934.1 )DECLARE num_fix INT;BEGINnum_fix := 0;DBMS_REPAIR.FIX_CORRUPT_BLOCKS (SCHEMA_NAME => '&schema_name',OBJECT_NAME=> '&object_name',OBJECT_TYPE => dbms_repair.table_object,REPAIR_TABLE_NAME => 'REPAIR_TABLE',FIX_COUNT=> num_fix); DBMS_OUTPUT.PUT_LINE('num fix: ' || to_char(num_fix));END;/REM Allow future DML statements to skip the corrupted blocks:BEGINDBMS_REPAIR.SKIP_CORRUPT_BLOCKS (SCHEMA_NAME => '&schema_name',OBJECT_NAME => '&object_name',OBJECT_TYPE => dbms_repair.table_object,FLAGS => dbms_repair.SKIP_FLAG);END;/
此文参考文献
详细请参考:
Note 556733.1DBMS_REPAIR SCRIPT
坏块属于LOB段:
NOTE 293515.1 ORA-1578 ORA-26040 in a LOB segment - Script to solve the errors
其他
Note 453278.1Error DBV-201 Marked Corrupt For Invalid Redo ApplicationNote 1459778.1Use RMAN to format corrupt data block which is not part of any objectNote 336133.1How to Format Corrupted Block Not Part of Any SegmentNote 556733.1DBMS_REPAIR SCRIPTNote 293515.1ORA-1578 ORA-26040 in a LOB segment - Script to solve the errors
文章转载自数据与人,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




