【Oracle坏块】Oracle坏块介绍 & 坏块类型:ALL ZERO

一、介绍

  v$DATABASE_BLOCK_CORRUPTION中的CORRUPTION_TYPE有以下几种情况:

  1、ALL ZERO

  ------磁盘上的块标头仅包含零。如果该块从未填充,并且位于Oracle7文件中,则该块可能有效。对于空块,缓冲区将重新格式化为Oracle8标准。

  2、FRACTURED

  ------块头看起来合理,但块的前面和后面是不同的版本。

  3、CHECKSUM

  ------可选检查值显示块不是自一致的。不可能确切地确定检查值失败的原因,但是它可能失败,因为块中间的扇区来自不同的版本。

  4、CORRUPT

  ------锁被错误识别或不是数据块(例如,数据块地址丢失)。

  5、LOGICAL

  ------块在逻辑上已损坏。

  6、NOLOGGING

  ------块没有重做日志项(例如,主数据库上的NOLOGGING操作可能会在物理备用数据库上引入这种类型的损坏)。

二、模拟几种corrupt情况

创建测试表空间和表

SQL> create tablespace test datafile '/u01/app/oracle/oradata/T1/test.dbf' size 32m;

SQL> create table test tablespace test;

SQL> declare
i number;
begin
for i in 1..10000 loop
insert into test values(i,'NB');
end loop;
commit;
end;
/

SQL> alter system flush buffer_cache;

 查看TEST表在OS上的物理位置

select dbms_rowid.rowid_relative_fno(rowid) rfn,dbms_rowid.rowid_block_number(rowid) bln,dbms_rowid.rowid_row_number(rowid) rn from test where rownum<=5;

       RFN      BLN          RN
---------- ---------- ----------
        21      131           0
        21      131           1
        21      131           2
        21      131           3
        21      131           4

查看TEST的表空间的信息

SQL> select ts.ts#,df.file#,df.name from v$datafile df,v$tablespace ts where ts.ts#=df.ts# and ts.name='TEST';

       TS#     FILE#  NAME
---------- ---------- --------------------------------------------------
         7       21   /u01/app/oracle/oradata/T1/pdb/test.dbf

RMAN下备份数据文件以用来恢复

RMAN> backup datafile 21;

 

1、模拟ALL ZERO

查看test数据

SQL> select count(*) from scott.test;

  COUNT(*)
----------
     10000

OS下使用dd命令

[oracle@T1 ~]$ dd if=/dev/zero of=/u01/app/oracle/oradata/T1/pdb/test.dbf bs=8192 count=1 seek=131 conv=notrunc
1+0 records in
1+0 records out
8192 bytes (8.2 kB) copied, 0.000155588 s, 52.7 MB/s

先刷新数据缓冲区,再次查看TEST表

SQL> alter system  flush buffer_cache;

System altered.

SQL> select count(*) from test;
select count(*) from test
       *
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 21, block # 131)
ORA-01110: data file 21: '/u01/app/oracle/oradata/T1/pdb/test.dbf'

发现坏块,查看视图发生坏块类型为ALL ZERO

SQL> select * from v$database_block_corruption;

     FILE#     BLOCK#     BLOCKS CORRUPTION_CHANGE# CORRUPTIO     CON_ID
---------- ---------- ---------- ------------------ --------- ----------
        21        131          1                  0  ALL ZERO          3

 

三、恢复方法

------恢复最先要考虑的一定要是备份恢复

1、RMAN

RMAN> restore datafile 21;
RMAN> recover datafile 21;

 

2、BBED

ALL ZERO类型的坏块无法用BBED,报错无效块类型,命令无法使用

BBED> set file 21
    FILE#              21

BBED> set block 131
    BLOCK#             131

BBED> map /v
 File: /u01/app/oracle/oradata/T1/pdb/test.dbf (21)
 Block: 131                                   Dba:0x05400083
------------------------------------------------------------
BBED-00400: invalid blocktype (00)

BBED> dump /v count 128
 File: /u01/app/oracle/oradata/T1/pdb/test.dbf (21)
 Block: 131     Offsets:    0 to  127  Dba:0x05400083
-------------------------------------------------------
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................

 <16 bytes per line>

 

3、DBMS_REPAIR包

DBMS_REPAIR包(丢失坏块数据)可以标记和跳过坏块

1)创建管理表(DBMS_REPAIR包前三项值不变,最后一项填写所属表空间)

SQL> exec DBMS_REPAIR.ADMIN_TABLES('REPAIR_TABLE',1,1,'TEST');

PL/SQL procedure successfully completed.

SQL> exec DBMS_REPAIR.ADMIN_TABLES('ORPHAN_TABLE',2,1,'TEST');

PL/SQL procedure successfully completed.

2)检查坏块 DBMA_REPAIR.CHECK_OBJECT存储包(corrupt_count不变)

SQL> set serveroutput on;
SQL>   1  declare
  2  i number;
  3  begin
  4  DBMS_REPAIR.CHECK_OBJECT(schema_name => 'SYS',      ------坏块对象所属的用户名
  5                  object_name => 'TEST',              ------表名
  6                  corrupt_count => i);
  7  DBMS_OUTPUT.PUT_LINE(TO_CHAR(i));
  8 end;
  9 /
1 ------正常情况下应该为0
PL/SQL procedure successfully completed.

如果有坏块,可以在创建的REPAIR_TABLE中查看块损坏的信息SQL:

SQL> set linesize 200
SQL> col OBJECT_NAME for a11
SQL> col CORRUPT_DESCRIPTION for a25
SQL> col REPAIR_DESCRIPTION for a30

SQL> SELECT object_name relative_file_id,block_id,marked_corrupt,corrupt_description,repair_description,CHECK_TIMESTAMP FROM repair_table;

OBJECT_NAME RELATIVE_FILE_ID   BLOCK_ID MARKED_COR CORRUPT_DESCRIPTION            REPAIR_DESCRIPTION             CHECK_TIME
----------- ---------------- ---------- ---------- ------------------------------ ------------------------------ ----------
TEST                      21        131 TRUE                                      mark block software corrupt    30-JUL-21

3)跳过坏块

之前虽然定位了坏块位置,但是如果访问TABAL还是会报错,这里需要用skip_corrupt_blocks来跳过坏块(flags不变)

SQL> exec DBMS_REPAIR.SKIP_CORRUPT_BLOCKS(schema_name => 'SYS',object_name => 'TEST',flags => 1);

PL/SQL procedure successfully completed.

SQL> select count(*) from test;

  COUNT(*)
----------
      9395

这里看出10000-9395=605,一共丢失了605行的数据。

4)处理index上的无效键值

DECLARE
   i    NUMBER;
BEGIN
   DBMS_REPAIR.dump_orphan_keys (schema_name         => 'SYS',            --SCHEMA用户
                                 object_name         => 'IDX_TEST_ID',        --索引名
                                 object_type         => 2,
                                 repair_table_name   => 'REPAIR_TABLE',
                                 orphan_table_name   => 'ORPHAN_TABLE',
                                 key_count           => i);
END;

5)查看之前生成的ORPHAN_TABLE可以直到丢失行的信息

SQL> select * from orphan_table;

6)重建freelist:rebuid_freelists

exec dbms_repair.rebuild_freelists(schema_name => 'SYS'   --所属用户SCHEMA
                        ,object_name => 'TEST'            --表名
                        );

 

3、CATS方式复制(EXP/IMP)

设置10231事件(这个事件让Oracle跳过只进行全表扫描的某些类型的损坏块,因此允许输出或“创建表作为选择“类型的操作,以便从没有损坏块的表中检索行,损坏块中的数据丢失。

SQL> ALTER SYSTEM SET EVENTS '10231 trace name context forever,level 10';

System altered.

创建一个临时表,把TEST中除坏块以外的数据都导出来(如果表大,可以把表单独导出)

SQL> create table recover_data_temp as select * from test;

Table created.

导出表

[oracle@T1 pdb]$ exp "'sys/oracle@pdb as sysdba'" file=test.dmp tables=test;

导入表

SQL> drop table test;

Table dropped.

[oracle@T1 pdb]$ imp "'sys/oracle@pdb as sysdba'" file=test.dmp tables=test;

验证

SQL> select count(*) from test;

  COUNT(*)
----------
      9395

同样也是丢失了605行的数据

取消10231 events

SQL> alter system set events='10231 trace name context off';

System altered.

 

posted @ 2021-07-30 15:18  蟹Bro  阅读(959)  评论(0编辑  收藏  举报