1. 程式人生 > >Oracle數據塊損壞的恢復實例

Oracle數據塊損壞的恢復實例

instance 3.1 point 簡單 object alter 會有 put -c

測試環境:11.2.0.4

  • 1.構建數據塊損壞的測試環境
  • 2.有備份:常規恢復壞塊
  • 3.無備份:跳過壞塊

1.構建數據塊損壞的測試環境

1.1 創建測試表

--Create Table t_test
conn jingyu/jingyu
drop table t_test purge;
create table t_test (id number, name char(2000));

--Insert data
insert into t_test values(1, ‘alfred 1‘);
insert into t_test values(2, ‘alfred 2‘);
insert into t_test values(3, ‘alfred 3‘);
insert into t_test values(4, ‘alfred 4‘);
insert into t_test values(5, ‘alfred 5‘);
insert into t_test values(6, ‘alfred 6‘);
insert into t_test values(7, ‘alfred 7‘);
insert into t_test values(8, ‘alfred 8‘);
insert into t_test values(9, ‘alfred 9‘);
insert into t_test values(10, ‘alfred 10‘);
commit;

--Create Index
create index idx_t_test_1 on t_test(id);

--Statistics
--analyze table t_test compute statistics;
EXEC DBMS_STATS.gather_table_stats(‘JINGYU‘, ‘T_TEST‘, cascade => TRUE);

1.2 查詢表中每一行對應的文件號和塊號

--查詢t_test表中每一行對應的文件和塊號
select blocks from user_tables where table_name = ‘T_TEST‘;

select dbms_rowid.rowid_relative_fno(rowid) R_FNO,
dbms_rowid.rowid_block_number(rowid) b_no, id
from t_test
order by 1,2;

--這裏對象占用塊數的查詢前後不匹配,與書中不符,但不影響實驗,結果如下: 
SQL> select blocks from user_tables where table_name = ‘T_TEST‘;

    BLOCKS
----------
         5

SQL> select dbms_rowid.rowid_relative_fno(rowid) R_FNO,
  2  dbms_rowid.rowid_block_number(rowid) b_no, id
  3  from t_test
  4  order by 1,2;

     R_FNO       B_NO         ID
---------- ---------- ----------
         6       3892          1
         6       3892          2
         6       3892          3
         6       3893          4
         6       3893          5
         6       3893          6
         6       3894          7
         6       3894          8
         6       3894          9
         6       3895         10

10 rows selected.

1.3 使用bbed工具模擬破壞6號數據文件的3893數據塊

關於bbed的編譯和使用可參考

  • 《Oracle 11g 編譯使用BBED》

1.3.1 準備bbed配置文件:
編輯/tmp/bbed.par參數配置文件

--編輯/tmp/bbed.par參數配置文件
blocksize=8192
listfile=/tmp/listfile.txt
mode=edit

--編輯/tmp/listfile.txt文件 
SQL> select file#||‘ ‘||name||‘ ‘||bytes from v$datafile ;

FILE#||‘‘||NAME||‘‘||BYTES
--------------------------------------------------------------------------------
1 +DATA1/jyzhao/datafile/system.256.919998779 786432000
2 +DATA1/jyzhao/datafile/sysaux.257.919998781 891289600
3 +DATA1/jyzhao/datafile/undotbs1.258.919998783 125829120
4 +DATA1/jyzhao/datafile/users.259.919998789 13107200
5 +DATA1/jyzhao/datafile/undotbs2.264.919999419 78643200
6 +DATA1/jyzhao/datafile/dbs_d_jingyu.268.927427887 104857600
7 +DATA1/jyzhao/datafile/dbs_i_jingyu.270.927427891 31457280
8 +DATA1/jyzhao/datafile/soe.278.939295201 104857600
9 +DATA1/jyzhao/datafile/dbs_d_jingyu.277.939295229 104857600

由於bbed不能直接操作ASM裏面的數據文件,所以需把對應的數據文件轉儲出來:

RMAN> backup as copy datafile 6 format ‘/opt/app/oracle/datafile/dbs_d_jingyu01.dbf‘;
--mount 
RMAN> switch datafile 6 to copy;
RMAN> recover datafile 6;
RMAN> alter database open;

--編輯/tmp/listfile.txt,添加6號文件信息
vi /tmp/listfile.txt
6 /opt/app/oracle/datafile/dbs_d_jingyu01.dbf 104857600

SQL> alter system checkpoint;

測試調用bbed正常:

--調用bbed
cd /tmp
bbed parfile=bbed.par

1.3.2 破壞數據文件6的3893數據塊

[[email protected] tmp]$ bbed parfile=bbed.par
Password: 

BBED: Release 2.0.0.0.0 - Limited Production on Wed Mar 22 15:28:00 2017

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

BBED> set dba 6,3893 
        DBA             0x01800f35 (25169717 6,3893)

BBED> find /c alfred
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893             Offsets: 2170 to 2681           Dba:0x01800f35
------------------------------------------------------------------------
 616c6672 65642036 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 

 <32 bytes per line>

BBED> f
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893             Offsets: 4179 to 4690           Dba:0x01800f35
------------------------------------------------------------------------
 616c6672 65642035 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 

 <32 bytes per line>

BBED> f
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893             Offsets: 6188 to 6699           Dba:0x01800f35
------------------------------------------------------------------------
 616c6672 65642034 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 

 <32 bytes per line>

BBED> f
BBED-00212: search string not found


BBED> dump /v dba 6,3893 offset 2170 count 64
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893    Offsets: 2170 to 2233  Dba:0x01800f35
-------------------------------------------------------
 616c6672 65642036 20202020 20202020 l alfred 6        
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 

 <16 bytes per line>

BBED> dump /v dba 6,3893 offset 4179 count 64
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893    Offsets: 4179 to 4242  Dba:0x01800f35
-------------------------------------------------------
 616c6672 65642035 20202020 20202020 l alfred 5        
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 

 <16 bytes per line>

BBED> dump /v dba 6,3893 offset 6188 count 64
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893    Offsets: 6188 to 6251  Dba:0x01800f35
-------------------------------------------------------
 616c6672 65642034 20202020 20202020 l alfred 4        
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 
 20202020 20202020 20202020 20202020 l                 

 <16 bytes per line>

BBED> modify 901010 dba 6,3893
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
 File: /opt/app/oracle/datafile/dbs_d_jingyu01.dbf (6)
 Block: 3893             Offsets: 6188 to 6251           Dba:0x01800f35
------------------------------------------------------------------------
 0dbf9272 65642034 20202020 20202020 20202020 20202020 20202020 20202020 
 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020 

 <32 bytes per line>

BBED> exit

1.3.3 使用dbv檢查文件

[[email protected] tmp]$ dbv file=/opt/app/oracle/datafile/dbs_d_jingyu01.dbf

DBVERIFY: Release 11.2.0.4.0 - Production on Wed Mar 22 15:31:50 2017

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

DBVERIFY - Verification starting : FILE = /opt/app/oracle/datafile/dbs_d_jingyu01.dbf
Page 3893 is marked corrupt
Corrupt block relative dba: 0x01800f35 (file 6, block 3893)
Bad check value found during dbv: 
Data in bad block:
 type: 6 format: 2 rdba: 0x01800f35
 last change scn: 0x0000.003b68be seq: 0x1 flg: 0x06
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x68be0601
 check value in block header: 0x6485
 computed block checksum: 0xd398



DBVERIFY - Verification complete

Total Pages Examined         : 12800
Total Pages Processed (Data) : 2512
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 989
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 9025
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 273
Total Pages Marked Corrupt   : 1
Total Pages Influx           : 0
Total Pages Encrypted        : 0
Highest block SCN            : 3893454 (0.3893454)
[[email protected] tmp]$ 

2.有備份:常規恢復

數據庫有有效的RMAN備份,那麽很簡單,直接恢復損害數據塊即可。
RMAN> blockrecover datafile 6 block 3893;

常規恢復輸出類似下面這樣:

RMAN> blockrecover datafile 6 block 3893;

Starting recover at 22-MAR-17
using target database control file instead of recovery catalog
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=148 instance=jyzhao1 device type=DISK

channel ORA_DISK_1: restoring block(s)
channel ORA_DISK_1: specifying block(s) to restore from backup set
restoring blocks of datafile 00006
channel ORA_DISK_1: reading from backup piece +FRA1/jyzhao/backupset/2017_03_22/nnndf0_tag20170322t123922_0.463.939299963
channel ORA_DISK_1: piece handle=+FRA1/jyzhao/backupset/2017_03_22/nnndf0_tag20170322t123922_0.463.939299963 tag=TAG20170322T123922
channel ORA_DISK_1: restored block(s) from backup piece 1
channel ORA_DISK_1: block restore complete, elapsed time: 00:00:01

starting media recovery
media recovery complete, elapsed time: 00:00:04

Finished recover at 22-MAR-17

恢復完成後可以正常訪問。

3.無備份:跳過壞塊

3.1 查看AFN和RFN

絕對數據文件號:AFN是數據文件在整個系統範圍內的編號。
相對數據文件號:RFN是數據文件在表空間範圍內的編號。
兩個文件可能有相同的RFN,但是不會有相同的AFN。

獲取普通文件的AFN和RFN:
select tablespace_name, file_id "AFN", relative_fno "RFN" from dba_data_files;

SQL> select tablespace_name, file_id "AFN", relative_fno "RFN" from dba_data_files;

TABLESPACE_NAME                       AFN        RFN
------------------------------ ---------- ----------
USERS                                   4          4
UNDOTBS1                                3          3
SYSAUX                                  2          2
SYSTEM                                  1          1
UNDOTBS2                                5          5
DBS_D_JINGYU                            6          6
DBS_I_JINGYU                            7          7
SOE                                     8       1024
DBS_D_JINGYU                            9          9

9 rows selected.

註意:實驗發現,大文件表空間的RFN固定為1024。

獲取臨時文件的AFN和RFN:
select tablespace_name, file_id + value "AFN", relative_fno "RFN" from dba_temp_files, v$parameter where name = ‘db_files‘;

SQL> select tablespace_name, file_id + value "AFN", relative_fno "RFN" from dba_temp_files, v$parameter where name = ‘db_files‘;

TABLESPACE_NAME                       AFN        RFN
------------------------------ ---------- ----------
TEMP_JINGYU                           202          1
TEMP                                  201          1

3.2 創建 REPAIR_TABLE 和 ORPHAN_KEY_TABLE
REPAIR_TABLE用來記錄錯誤檢查結果,ORPHAN_KEY_TABLE用來記錄表壞塊中記錄在索引中對應鍵值。

--通過如下存儲過程創建 REPAIR_TABLE 和 ORPHAN_KEY_TABLE
--Repair Table
declare
begin
    dbms_repair.admin_tables(
        table_name => ‘REPAIR_TABLE‘,
        table_type => dbms_repair.repair_table,
        action => dbms_repair.create_action,
        tablespace => ‘USERS‘
    );
end;
/

select owner, object_name, object_type from dba_objects where object_name like ‘%REPAIR_TABLE‘;

--Orphan Key Table
declare
begin
    dbms_repair.admin_tables(
        table_name => ‘ORPHAN_KEY_TABLE‘,
        table_type => dbms_repair.orphan_table,
        action => dbms_repair.create_action,
        tablespace => ‘USERS‘
    );
end;
/

select owner, object_name, object_type from dba_objects where object_name like ‘%ORPHAN_KEY_TABLE‘;

--不再需要時,可以通過下面的存儲過程刪除 REPAIR_TABLE 和 ORPHAN_KEY_TABLE 這兩個表:
--DROP REPAIR_TABLE
BEGIN
    DBMS_REPAIR.ADMIN_TABLES (
        TABLE_NAME => ‘REPAIR_TABLE‘,
        TABLE_TYPE => dbms_repair.repair_table,
        ACTION => dbms_repair.drop_action);
END;
/

--DROP ORPHAN_KEY_TABLE
BEGIN
    DBMS_REPAIR.ADMIN_TABLES (
        TABLE_NAME => ‘ORPHAN_KEY_TABLE‘,
        TABLE_TYPE => dbms_repair.orphan_table,
        ACTION => dbms_repair.drop_action);
END;
/

3.3 使用CHECK_OBJECT過程檢測壞塊

set serveroutput on
declare
    rpr_count int;
begin
    rpr_count := 0;
    dbms_repair.check_object(
        schema_name => ‘JINGYU‘,
        object_name => ‘T_TEST‘,
        repair_table_name => ‘REPAIR_TABLE‘,
        corrupt_count => rpr_count
    );
    dbms_output.put_line(‘repair count: ‘ || to_char(rpr_count));
end;
/

select object_name, block_id, corrupt_type, marked_corrupt, corrupt_description, repair_description from repair_table;

執行結果:

SQL> set serveroutput on
SQL> declare
  2     rpr_count int;
  3  begin
  4     rpr_count := 0;
  5     dbms_repair.check_object(
  6             schema_name => ‘JINGYU‘,
  7             object_name => ‘T_TEST‘,
  8             repair_table_name => ‘REPAIR_TABLE‘,
  9             corrupt_count => rpr_count
 10     );
 11     dbms_output.put_line(‘repair count: ‘ || to_char(rpr_count));
 12  end;
 13  /
repair count: 1

PL/SQL procedure successfully completed.

SQL> select object_name, block_id, corrupt_type, marked_corrupt, corrupt_description, repair_description from repair_table;

OBJECT_NAME                      BLOCK_ID CORRUPT_TYPE MARKED_COR
------------------------------ ---------- ------------ ----------
CORRUPT_DESCRIPTION
--------------------------------------------------------------------------------
REPAIR_DESCRIPTION
--------------------------------------------------------------------------------
T_TEST                               3893         6148 TRUE

mark block software corrupt

如果marked_corrupt不是true,則需要使用fix_corrupt_blocks過程修復:

declare
    fix_count int;
begin
    fix_count := 0;
    dbms_repair.fix_corrupt_blocks(
        schema_name => ‘JINGYU‘,
        object_name => ‘T_TEST‘,
        object_type => dbms_repair.table_object,
        repair_table_name => ‘REPAIR_TABLE‘,
        fix_count => fix_count
    );
    dbms_output.put_line(‘fix count: ‘ || to_char(fix_count));
end;
/

這裏實驗此步驟執行不執行都可以。

3.4 使用DUMP_ORPHAN_KEYS過程來保存壞塊中的索引鍵值

select object_name, block_id, marked_corrupt from repair_table;

select index_name from dba_indexes where table_name in (select distinct object_name from repair_table);

SQL> select object_name, block_id, marked_corrupt from repair_table;

OBJECT_NAME                      BLOCK_ID MARKED_COR
------------------------------ ---------- ----------
T_TEST                               3893 TRUE

SQL> select index_name from dba_indexes where table_name in (select distinct object_name from repair_table);

INDEX_NAME
------------------------------
IDX_T_TEST_1

這時還存在著一個潛在的問題。
就是表有壞塊,但索引沒有損壞,通過表掃描會出現錯誤,但是通過索引掃描仍然可以返回結果,這會造成數據的不一致性。
比如,這裏我知道id = 4的記錄:

SQL> select * from jingyu.t_test where id = 4;
select * from jingyu.t_test where id = 4
                     *
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 6, block # 3893)
ORA-01110: data file 6: ‘/opt/app/oracle/datafile/dbs_d_jingyu01.dbf‘


SQL> select id from jingyu.t_test where id = 4;

        ID
----------
         4

使用DUMP_ORPHAN_KEYS過程來保存壞塊中的索引鍵值:

set serveroutput on
declare
    key_count int;
begin
    key_count := 0;
    dbms_repair.dump_orphan_keys(
        schema_name => ‘JINGYU‘,
        object_name => ‘IDX_T_TEST_1‘,
        object_type => dbms_repair.index_object,
        repair_table_name => ‘REPAIR_TABLE‘,
        orphan_table_name => ‘ORPHAN_KEY_TABLE‘,
        key_count => key_count
    );
    dbms_output.put_line(‘orphan key count: ‘ || to_char(key_count));
end;
/

執行結果如下:

SQL> set serveroutput on
SQL> declare
  2     key_count int;
  3  begin
  4     key_count := 0;
  5     dbms_repair.dump_orphan_keys(
  6             schema_name => ‘JINGYU‘,
  7             object_name => ‘IDX_T_TEST_1‘,
  8             object_type => dbms_repair.index_object,
  9             repair_table_name => ‘REPAIR_TABLE‘,
 10             orphan_table_name => ‘ORPHAN_KEY_TABLE‘,
 11             key_count => key_count
 12     );
 13     dbms_output.put_line(‘orphan key count: ‘ || to_char(key_count));
 14  end;
 15  /
orphan key count: 3

PL/SQL procedure successfully completed.

這樣當之後執行完SKIP_CORRUPT_BLOCKS操作後,就可以重新建立索引了(對每個索引都要執行DUMP_ORPHAN_KEYS過程)。

3.5 使用skip_corrupt_blocks過程來跳過壞塊
執行skip_corrupt_blocks過程,使後續DML操作跳過壞塊:

begin
    dbms_repair.skip_corrupt_blocks (
        schema_name => ‘JINGYU‘,
        object_name => ‘T_TEST‘,
        object_type => dbms_repair.table_object,
        flags => dbms_repair.skip_flag
    );
end;
/

執行結果:

SQL> select count(1) from jingyu.t_test;
select count(1) from jingyu.t_test
                            *
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 6, block # 3893)
ORA-01110: data file 6: ‘/opt/app/oracle/datafile/dbs_d_Jingyu01.dbf‘


SQL> begin
  2     dbms_repair.skip_corrupt_blocks (
  3             schema_name => ‘JINGYU‘,
  4             object_name => ‘T_TEST‘,
  5             object_type => dbms_repair.table_object,
  6             flags => dbms_repair.skip_flag
  7     );
  8  end;
  9  /

PL/SQL procedure successfully completed.

SQL>  select count(1) from jingyu.t_test;

  COUNT(1)
----------
         7

3.6 重建freelist
如果不想使用CTAS方式重建表而仍是在原表上修復,則需要重建對象的Freelist,防止這個數據塊以後被加到freelist中。使用下面的方法:

declare
begin
    dbms_repair.rebuild_freelists (
        schema_name => ‘JINGYU‘,
        object_name => ‘T_TEST‘,
        object_type => dbms_repair.table_object
    );
end;
/

這裏實際已知壞塊不在freelist中,所以不需要執行,執行會報錯如下錯誤:

SQL> declare
  2  begin
  3     dbms_repair.rebuild_freelists (
  4             schema_name => ‘JINGYU‘,
  5             object_name => ‘T_TEST‘,
  6             object_type => dbms_repair.table_object
  7     );
  8  end;
  9  /
declare
*
ERROR at line 1:
ORA-10614: Operation not allowed on this segment
ORA-06512: at "SYS.DBMS_REPAIR", line 401
ORA-06512: at line 3

3.7 重建索引
目前索引和數據塊仍然存在不一致,必須要重建索引:

--以id=4為例,索引和數據塊依然存在不一致:
SQL> select * from jingyu.t_test where id = 4;

no rows selected

SQL> select id from jingyu.t_test where id = 4;

        ID
----------
         4

--重建索引,不能采用rebuild,只能drop後再create。因為rebuild數據源來自索引:
--測試rebuild發現的確還存在不一致:
SQL> alter index jingyu.idx_t_test_1 rebuild;

Index altered.

SQL> select id from jingyu.t_test where id = 4;

        ID
----------
         4

--先drop再create index,確認一致:
SQL> drop index jingyu.idx_t_test_1;

Index dropped.

SQL> create index jingyu.idx_t_test_1 on jingyu.t_test(id);

Index created.

SQL> select id from jingyu.t_test where id = 4;

no rows selected

當然,如果此時使用dbv檢查數據文件,依然是有壞塊的,上面所有操作只是跳過壞塊,並沒有解決。

[[email protected] ~]$ dbv file=/opt/app/oracle/datafile/dbs_d_jingyu01.dbf

DBVERIFY: Release 11.2.0.4.0 - Production on Wed Mar 22 17:29:42 2017

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

DBVERIFY - Verification starting : FILE = /opt/app/oracle/datafile/dbs_d_jingyu01.dbf
Page 3893 is marked corrupt
Corrupt block relative dba: 0x01800f35 (file 6, block 3893)
Bad check value found during dbv: 
Data in bad block:
 type: 6 format: 2 rdba: 0x01800f35
 last change scn: 0x0000.003b68be seq: 0x1 flg: 0x06
 spare1: 0x0 spare2: 0x0 spare3: 0x0
 consistency value in tail: 0x68be0601
 check value in block header: 0x6485
 computed block checksum: 0xd398



DBVERIFY - Verification complete

Total Pages Examined         : 12800
Total Pages Processed (Data) : 2512
Total Pages Failing   (Data) : 0
Total Pages Processed (Index): 989
Total Pages Failing   (Index): 0
Total Pages Processed (Other): 9025
Total Pages Processed (Seg)  : 0
Total Pages Failing   (Seg)  : 0
Total Pages Empty            : 273
Total Pages Marked Corrupt   : 1
Total Pages Influx           : 0
Total Pages Encrypted        : 0
Highest block SCN            : 3907507 (0.3907507)

善後工作(與數據塊恢復無關):
養成一個習慣,做任何實驗,如果對實驗環境改動較大,建議實驗完畢後,盡量恢復到正常狀態,避免今後測試其他案例時現修復環境。
我這裏就是把實驗環境恢復(6號文件恢復為原來的ASM存儲上):

RMAN> list copy  of datafile 6;

using target database control file instead of recovery catalog
List of Datafile Copies
=======================

Key     File S Completion Time Ckp SCN    Ckp Time       
------- ---- - --------------- ---------- ---------------
18      6    A 22-MAR-17       3895505    22-MAR-17      
        Name: +DATA1/jyzhao/datafile/dbs_d_jingyu.268.939306177
        Tag: TAG20170322T142256

16      6    A 22-MAR-17       3817798    22-MAR-17      
        Name: /opt/app/oracle/datafile/dbs_d_Jingyu01.dbf

14      6    A 22-MAR-17       3817798    22-MAR-17      
        Name: +FRA1/jyzhao/datafile/dbs_d_jingyu.368.939306031
        Tag: TAG20170322T142027


RMAN> switch datafile 6 to copy;

datafile 6 switched to datafile copy "+DATA1/jyzhao/datafile/dbs_d_jingyu.268.939306177"

RMAN> recover datafile 6;

Starting recover at 22-MAR-17
allocated channel: ORA_DISK_1
channel ORA_DISK_1: SID=143 instance=jyzhao1 device type=DISK

starting media recovery
media recovery complete, elapsed time: 00:00:01

Finished recover at 22-MAR-17

RMAN> alter database open;

database opened

至此,已完成數據塊恢復實例的整個實驗。

此外,針對壞塊問題,還有一種方式是設置10231 event,具體可參考:

  • 《Oracle數據塊損壞篇之10231內部事件》

Reference

  • http://blog.itpub.net/4227/viewspace-68509/
  • 張曉明. 大話Oracle RAC[M]. 人民郵電出版社, 2011.

Oracle數據塊損壞的恢復實例