【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.