Oracle数据文件的坏块,可分为物理坏块和逻辑坏块

物理坏块(也可以称为介质坏块)指的是块格式本身是坏的,块内的数据没有任何意义。而逻辑坏块,
指的是块内的数据在逻辑是存在问题。比如说索引块的索引值没有按从小到大排列。
物理坏块一般是由于内存问题、OS问题、IO子系统问题和硬件引起,逻辑坏块一般是是由于Oracle Bug等原因引起。
Oracle数据文件的每个块,其块头为20字节。其定义如下:(来自于DSI401)
struct kcbh
{
    ub1 type_kcbh; /* block type */
    ub2 frmt_kcbh;
    ub1 spare1_kcbh;
    ub1 spare2_kcbh;
    krDBA rdba_kcbh; /* relative DBA */
    ub4 bas_kcbh; /* base of SCN */
    ub2 wrp_kcbh; /* wrap of SCN */
    ub1 seq_kcbh; /* sequence # of changes at the same scn */
    ub1 flg_kcbh;
    ub2 chkval_kcbh;
};  

在块头中,seq_kcbh(占用1字节,块头偏移14)有着特殊的含义,如果该值为0xff,则表示该块被标记为corruption。
下面我们做一个测试:
SQL> create table test.t1 as select * from dba_objects;
表已创建。
SQL> select header_file,header_block from dba_segments where segment_name=’T1′ and owner=’TEST’;
HEADER_FILE HEADER_BLOCK
----------- ------------
         10         1445
修改db_block_checksum参数值为TRUE,关闭数据库,我们用ultraedit修改10号文件的1447块的check sum(一个随便>0的数)及flag=0×04。然后再打开数据库。再执行下面的查询:
SQL> select count(*) from test.t1;
select count(*) from test.t1
*
ERROR 位于第 1 行:
ORA-01578: ORACLE 数据块损坏(文件号10,块号1447)
ORA-01110: 数据文件 10: ‘D:\ORACLE\ORADATA\XJ\TEST01.DBF’
由于非系统表空间在db_block_checksum参数设为FALSE时,会忽略checksum的检查。所以这里为了测试的方便设置为TRUE。
从上面的错误信息来看,块号1447这个块已经坏了,报的错误是经典的ORA-01578错误。
我们用dbv检查一下这个文件:
D:\oracle\oradata\XJ>dbv file=TEST01.dbf blocksize=2048
DBVERIFY: Release 9.2.0.1.0 - Production on 星期一 2月 23 17:20:43 2009
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
DBVERIFY - 验证正在开始 : FILE = TEST01.dbf
标记为损坏的页1447
***
Corrupt block relative dba: 0×028005a7 (file 10, block 1447)
Bad check value found during dbv:
Data in bad block -
type: 6 format: 2 rdba: 0×028005a7
last change scn: 0×0000.0023b43e seq: 0×2 flg: 0×04
consistency value in tail: 0xb43e0602
check value in block header: 0xf0f0, computed block checksum: 0×3a4f
spare1: 0×0, spare2: 0×0, spare3: 0×0
***
DBVERIFY - 验证完成
检查的页总数         :56660
处理的页总数(数据):53947
失败的页总数(数据):0
处理的页总数(索引):30
失败的页总数(索引):0
处理的页总数(其它):2669
处理的总页数 (段)  : 0
失败的总页数 (段)  : 0
空的页总数            :13
标记为损坏的总页数:1
汇入的页总数           :0
dbv检查发现了坏块(check错误)。
而如果用analyze命令检查也会发现有坏块:
SQL> analyze table test.t1 validate structure;
analyze table test.t1 validate structure
*
ERROR 位于第 1 行:
ORA-01578: ORACLE 数据块损坏(文件号10,块号1447)
ORA-01110: 数据文件 10: ‘D:\ORACLE\ORADATA\XJ\TEST01.DBF’
我们用dbms_repair来处理这个坏块(实际上如果只是checksum坏了,可以修改checksum为正确的值。但实际情况下,checksum坏了往往意味着坏内的数据已经坏了,大多数情况下只能丢弃):
SQL>> begin
  2    dbms_repair.admin_tables (
  3      table_name => ’REPAIR_TABLE’,
  4      table_type => dbms_repair.repair_table,
  5      action => dbms_repair.create_action,
  6      tablespace => ’SYSTEM’);
  7  end;
  8  /
PL/SQL 过程已成功完成。
SQL> set serveroutput on
SQL> declare
  2    rpr_count int;
  3  begin
  4    rpr_count := 0;
  5    dbms_repair.check_object (
  6      schema_name => ’TEST’,
  7      object_name => ’T1′,
  8      repair_table_name => ’REPAIR_TABLE’,
  9      corrupt_count => rpr_count);
10    dbms_output.put_line(’repair count: ’ || to_char(rpr_count));
11  end;
12  /
repair count: 1
PL/SQL 过程已成功完成。
SQL> select object_name, block_id, corrupt_type, marked_corrupt,corrupt_description,
2 repair_description from repair_table;
OBJECT_NAME     BLOCK_ID CORRUPT_TYPE MARKED_COR CORRUPT_DESCRIPTION  REPAIR_DESCRIPTION
------------- ---------- ------------ ---------- -------------------- --------------------
T1                  1447         6148 TRUE                            mark block software
                                                                      corrupt
T1                  1447         6148 TRUE                            mark block software
                                                                      corrupt
SQL> declare
  2    fix_count int;
  3    begin
  4      fix_count := 0;
  5      dbms_repair.fix_corrupt_blocks (
  6      schema_name => ’TEST’,
  7      object_name => ’T1′,
  8      object_type => dbms_repair.table_object,
  9      repair_table_name => ’REPAIR_TABLE’,
10      fix_count => fix_count);
11    dbms_output.put_line(’fix count: ’ || to_char(fix_count));
12  end;
13  /
fix count: 0
PL/SQL 过程已成功完成。
SQL> begin
  2    dbms_repair.skip_corrupt_blocks (
  3      schema_name => ’TEST’,
  4      object_name => ’T1′,
  5      object_type => dbms_repair.table_object,
  6      flags => dbms_repair.skip_flag);
  7  end;
  8  /
PL/SQL 过程已成功完成。
SQL> select table_name, skip_corrupt from dba_tables where table_name = ’T1′ and owner=’TEST’;
TABLE_NAME                     SKIP_COR
------------------------------ --------
T1                             ENABLED
SQL> select count(*) from test.t1;
  COUNT(*)
----------
     28762
SQL> alter system checkpoint;
系统已更改。
从上面可以看到,dbms_repair.fix_corrupt_blocks并不修复checksum错误,也不做坏块标记。通过dbv和用ultraedit检查块头,没有发现任何变化。但是通过dbms_repair.skip_corrupt_blocks过程在数据字典中将表设置为跳过坏块,则在查询时会跳过该块。
如果用RMAN备份该文件,而后还原该文件后,则这个坏块的seq_kcbh则被设为0xff。而此时用dbv检查该文件则显示的错误信息则为:
DBVERIFY - 验证正在开始 : FILE = TEST01.dbf
DBV-00200: 块, dba 41944487, 已经标记为崩溃
DBVERIFY - 验证完成
检查的页总数 :56655
处理的页总数(数据):53948
失败的页总数(数据):0
处理的页总数(索引):30
失败的页总数(索引):0
处理的页总数(其它):2669
处理的总页数 (段) : 0
失败的总页数 (段) : 0
空的页总数 :8
标记为损坏的总页数:0
汇入的页总数 :0
注意这里“标记为损坏的总页数”跟前一次检查的不一样,这里为“0”。
标签: 暂无标签
李波Joker

写了 46 篇文章,拥有财富 503,被 8 人关注

转播转播 分享分享 分享淘帖
回复

使用道具

成为第一个吐槽的人

您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

意见
反馈