首页  ·  知识 ·  数据库
Oracle坏块问题处理
网友  中国IT实验室     编辑:德仔   图片来源:网络
首先,制造坏块   view sourceprint?01 select tablespace_name,extent_management,SEGMENT_SPACE_MANAGEMENT from dba_
首先,制造坏块
  view sourceprint?01 select tablespace_name,extent_management,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces where tablespace_name='ETMCDB';
  02 TABLESPACE_NAME EXTENT_MAN SEGMEN
  03 ------------------------------ ---------- ------
  04 ETMCDB LOCAL AUTO
  05
  06 create table t1 (id number, c1 char(2000), c2 char(2000), c3 char(2000)) tablespace ETMCDB;
  07 insert into t1 VALUES (1, 'A', 'A', 'A');
  08 insert into t1 VALUES (2, 'A', 'A', 'A');
  09 insert into t1 VALUES (3, 'A', 'A', 'A');
  10 insert into t1 VALUES (4, 'A', 'A', 'A');
  11 insert into t1 VALUES (5, 'A', 'A', 'A');
  12 insert into t1 VALUES (6, 'A', 'A', 'A');
  13 insert into t1 VALUES (7, 'A', 'A', 'A');
  14 commit;
  15
  16 select id,rowid,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) from t1;
  17 ID ROWID DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)||'_'||DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
  18 ---------- ------------------ ---------------------------------------------------------------------------------
  19 1 AAAOZnAAHAAAAAUAAA 7_20
  20 2 AAAOZnAAHAAAAAVAAA 7_21
  21 3 AAAOZnAAHAAAAAWAAA 7_22
  22 4 AAAOZnAAHAAAAAXAAA 7_23
  23 5 AAAOZnAAHAAAAAYAAA 7_24
  24 6 AAAOZnAAGAAAABhAAA 6_97
  25 7 AAAOZnAAGAAAABiAAA 6_98
  26 7 rows selected.
  27
  28 SQL> select file#,name from v$datafile;
  29 FILE# NAME
  30 ---------- -----------------------
  31 <—More-->
  32 7 /u02/oradata/ETMCDB02.dbf
  33 <—More—>
  34
  35 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
  view sourceprint?01 SQL> startup
  02
  03 SQL> select * from t1;
  04 ERROR:
  05 ORA-01578: ORACLE data block corrupted (file # 7, block # 21)
  06 ORA-01110: data file 7: '/u02/oradata/ETMCDB02.dbf'
  07 no rows selected
  08
  09 SQL> SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents <BR>         WHERE file_id = &file and &block between block_id AND block_id + blocks - 1 ;
  10 Enter value for file: 7
  11 Enter value for block: 21
  12 old   1: SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents <BR>            WHERE file_id = &file and &block between block_id AND block_id + blocks - 1
  13 new   1: SELECT tablespace_name, owner,segment_name,segment_type FROM dba_extents <BR>            WHERE file_id = 7 and 21 between block_id AND block_id + blocks - 1
  14
  15 TABLESPACE OWNER      SEGMENT_NAME         SEGMENT_TYPE
  16 ---------- ---------- -------------------- ------------------
  17 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这个职位。
 
本文作者:网友 来源:中国IT实验室
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读
也许感兴趣的
我们推荐的
主题最新
看看其它的