Oracle坏块问题处理
曾经遇到过ORA-8103,01578的坏块错误记录下方法
首先,制造坏块
select tablespace_name,extent_management,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces where tablespace_name='ETMCDB'; TABLESPACE_NAME EXTENT_MAN SEGMEN ------------------------------ ---------- ------ ETMCDB LOCAL AUTO create table t1 (id number, c1 char(2000), c2 char(2000), c3 char(2000)) tablespace ETMCDB; insert into t1 VALUES (1, 'A', 'A', 'A'); insert into t1 VALUES (2, 'A', 'A', 'A'); insert into t1 VALUES (3, 'A', 'A', 'A'); insert into t1 VALUES (4, 'A', 'A', 'A'); insert into t1 VALUES (5, 'A', 'A', 'A'); insert into t1 VALUES (6, 'A', 'A', 'A'); insert into t1 VALUES (7, 'A', 'A', 'A'); commit; select id,rowid,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) from t1; ID ROWID DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)||'_'||DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) ---------- ------------------ --------------------------------------------------------------------------------- 1 AAAOZnAAHAAAAAUAAA 7_20 2 AAAOZnAAHAAAAAVAAA 7_21 3 AAAOZnAAHAAAAAWAAA 7_22 4 AAAOZnAAHAAAAAXAAA 7_23 5 AAAOZnAAHAAAAAYAAA 7_24 6 AAAOZnAAGAAAABhAAA 6_97 7 AAAOZnAAGAAAABiAAA 6_98 7 rows selected. SQL> select file#,name from v$datafile; FILE# NAME ---------- ----------------------- <—More--> 7 /u02/oradata/ETMCDB02.dbf <—More—> SQL> shutdown immediate;
修改Checksum的值
导出第31个块(算上os header block,物理上是32个块)来把它的变成坏块,使用dd考出data block 【更多关于DD请参考这里】
node1*orcl-/u02/oradata >dd if=/u02/oradata/ETMCDB02.dbf of=/u02/oradata/ETMCDB02_7_21.dd skip=21 bs=8192 count=1
1+0 records in
1+0 records out
8192 bytes (8.2 kB) copied, 0.00417351 seconds, 2.0 MB/s
这里涉及到了notrunc模式,如果没有指定notrunc的话那么需要再dd出65505个块,
node1*orcl-/u02/oradata >dd if=/u02/oradata/ETMCDB02.dbf of=/u02/oradata/ETMCDB02_7_65505.dd skip=22 bs=8192 count=65505
原因
node1*orcl-/home/oracle >ls -al /u02/oradata/
total 1159260
-rw-r--r-- 1 oracle dba 8192 Nov 15 15:23 ETMCDB02_7_21.dd
-rw-r----- 1 oracle dba 536879104 Nov 15 14:51 ETMCDB02.dbf
SQL> select (536879104-32*8192)/8192 from dual;
(536879104-32*8192)/8192
----------------------
65505
也可以不用这么麻烦,可以在导回时使用notrunc方法
之后用Ultraedit打开修改offset 16随便一个>0的数值,然后传回
node1*orcl-/u02/oradata > dd if=/u02/oradata/ETMCDB02_7_21.dd of=/u02/oradata/ETMCDB02.dbf seek=21 bs=8192 count=1 conv=notrunc
这里还有个小技巧就是直接用Ultraedit打开确定文件7号ETMCDB02.dbf后在UE中按CTRL+G,输入这个 块号*块大小的结果就可以了,比如这个例子就是21*8192
SQL> startup SQL> select * from t1; ERROR: ORA-01578: ORACLE data block corrupted (file # 7, block # 21) ORA-01110: data file 7: '/u02/oradata/ETMCDB02.dbf' no rows selected SQL> SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents
WHERE file_id = &file and &block between block_id AND block_id + blocks - 1 ; Enter value for file: 7 Enter value for block: 21 old 1: SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents
WHERE file_id = &file and &block between block_id AND block_id + blocks - 1 new 1: SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents
WHERE file_id = 7 and 21 between block_id AND block_id + blocks - 1 TABLESPACE OWNER SEGMENT_NAME SEGMENT_TYPE ---------- ---------- -------------------- ------------------ ETMCDB XXD T1 TABLE
node1*orcl-/u02/oradata >dbv file=ETMCDB02.dbf blocksize=8192
DBVERIFY: Release 10.2.0.1.0 - Production on Wed Nov 17 18:53:08 2010
Copyright (c) 1982, 2005, Oracle. All rights reserved.
DBVERIFY - Verification starting : FILE = ETMCDB02.dbf
Page 21 is marked corrupt
Corrupt block relative dba: 0x01c00015 (file 7, block 21)
Bad header found during dbv:
Data in bad block:
type: 6 format: 2 rdba: 0x01c00015
last change scn: 0x0000.005552a8 seq: 0x1 flg: 0x02
spare1: 0x0 spare2: 0x0 spare3: 0x0
consistency value in tail: 0x52a80601
check value in block header: 0x11
block checksum disabled
DBVERIFY - Verification complete
Total Pages Examined : 640
Total Pages Processed (Data) : 461
Total Pages Failing (Data) : 0
Total Pages Processed (Index): 1
Total Pages Failing (Index): 0
Total Pages Processed (Other): 45
Total Pages Processed (Seg) : 0
Total Pages Failing (Seg) : 0
Total Pages Empty : 132
Total Pages Marked Corrupt : 1
Total Pages Influx : 0
Highest block SCN : 5591720 (0.5591720)
使用DBMS_REPAIR “修复”坏块
set serveroutput on BEGIN DBMS_REPAIR.ADMIN_TABLES ( TABLE_NAME => 'REPAIR_TABLE', TABLE_TYPE => dbms_repair.repair_table, ACTION => dbms_repair.create_action, TABLESPACE => 'ETMCDB'); END; / DECLARE num_corrupt INT; BEGIN num_corrupt := 0; DBMS_REPAIR.CHECK_OBJECT ( SCHEMA_NAME => 'SYS', OBJECT_NAME => 'T1', REPAIR_TABLE_NAME => 'REPAIR_TABLE', corrupt_count => num_corrupt); DBMS_OUTPUT.PUT_LINE('number corrupt: ' || TO_CHAR (num_corrupt)); END; / BEGIN DBMS_REPAIR.SKIP_CORRUPT_BLOCKS ( SCHEMA_NAME => 'SYS', OBJECT_NAME => 'T1', OBJECT_TYPE => dbms_repair.table_object, FLAGS => dbms_repair.SKIP_FLAG); END; / SQL> select id from t1; ID ---------- 1 3 4 5 6 7 6 rows selected SQL> select object_name, block_id, corrupt_type, marked_corrupt,corrupt_description,repair_description from repair_table; OBJECT_NAME BLOCK_ID CORRUPT_TYPE MARKED_CORCORRUPT_DESCRIPTION REPAIR_DESCRIPTION ----------- -------- ------------ ------------------------------ -------------------------- T1 21 6148 TRUE mark block software corrupt SQL> alter system checkpoint; System altered.
看看这个DBMS_REPAIR“修复”到底做了些什么
node1*orcl-/u01/app/oracle/product/10.2.0/db_1/bin >bbed parfile=bbed.par
Password:
BBED: Release 2.0.0.0.0 - Limited Production on Wed Nov 17 19:01:05 2010
Copyright (c) 1982, 2005, Oracle. All rights reserved.
************* !!! For Oracle Internal Use only !!! ***************
BBED> set file 7
FILE# 7
BBED> set block 21
BLOCK# 21
BBED> dump
File: /u02/oradata/ETMCDB02.dbf (7)
Block: 21 Offsets: 0 to 511 Dba:0x01c00015
------------------------------------------------------------------------
06a20000 1500c001 a8525500 00000102 11000000 01000000 67e60000 a4525500
00000000 02003200 1100c001 0a000300 1e0a0000 87008000 0a061500 01200000
a8525500 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00010100 ffff1400 19080508 05080000 01001908 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
<32 bytes per line>
对比这个数据库没有被破坏时的情况
BBED> dump
File: /u02/oradata/ETMCDB02.dbf (7)
Block: 21 Offsets: 0 to 511 Dba:0x01c00015
------------------------------------------------------------------------
06a20000 1500c001 a8525500 00000102 00000000 01000000 67e60000 a4525500
<--More-->
<32 bytes per line>
而这时候查看Block内部,实际上DBMS_REPAIR没有对块做任何的修改只是跳过了该块。实际情况下,checksum坏了往往意味着坏内的数据已经坏了因为我们无法的值正确的Checksum的值,只能跳过。
那么看看RMAN能够对坏块做些什么
首先使用rman检查含有坏块的数据文件:
RMAN> backup validate datafile 7;
随后查看坏块信息v$database_block_corruption
SQL> select * from v$database_block_corruption;
FILE# BLOCK# BLOCKS CORRUPTION_CHANGE# CORRUPTIO
---------- ---------- ---------- ------------------ ---------
7 21 1 0 FRACTURED
使用rman进行块恢复:
RMAN> blockrecover datafile 7 block 21 from backupset;
如果执行BLOCKRECOVER CORRUPTION LIST会自动按照V$DATABASE_BLOCK_CORRUPTION进行修复
RMAN> BLOCKRECOVER CORRUPTION LIST;
随后确认坏块信息v$database_block_corruption
SQL> select * from v$database_block_corruption;
no rows selected
如果用RMAN备份该文件,而后还原该文件后,则这个坏块的seq_kcbh则被设为0xff。
神器BBED或者DD+UltraEdit
大概说一下如果数据块的损坏应该是offset@18也就是seq_kcbh被标记成0xff。这时检查alert.log如果看到 computed block checksum那么使用BBED其实很容易,进入然后打开损坏的数据块,offset到16,sum apply后oracle会算出正确的checksum值并且写回去。具体算法就是 computed block checksum后边会有一个数值那么转换成二进制和现有的offset 16 17做异或运算就可以算出正确的值。我也是最近才弄明白这种算法,正好复习。
最后还有一种exp+10231事件的终极方法,具体看链接内的eygle的文章。不过对于大表就是个灾难,希望能够在面临这类灾难时有可靠的RMAN备份可用,不然为了几个数据块而去exp..........简直就是侮辱了DBA这个职位。
参考文章
- 记一次ORA-8103错误的处理
- Oracle怎样标记坏块及一次数据恢复
- Oracle中模拟及修复数据块损坏
- 利用dd修改checksum值的过程
- 利用BBED修改checksum值的过程
- 怎样计算出正确的checksum值