Oracle 数据坏块的多种修复方式

2024年 2月 4日 62.4k 0

前言

Oracle 数据库的运行不可避免的会遇到各种各样的错误,就比如数据表出现坏块,此时,你这张表的数据就无法访问了,有什么好的办法可以恢复呢?

一、介绍

对于 Oracle 数据块物理损坏 的情形,通常可以分为两种情况:

有备份,通过 RMAN 恢复

无备份,通过 DBMS_REPAIR 修复

1、RMAN

有备份的情况下,这是很理想的情形,我们可以直接通过 RMAN 块介质恢复(BLOCK MEDIA RECOVERY)功能来完成受损块的恢复。

这里我是不建议恢复整个数据库或者数据库文件来修复这些少量受损的数据块,有点浪费时间。

可参考官方文档:Block Media Recovery with RMAN

2、DBMS_REPAIR

那如果没有任何备份怎么办? (PS:备份大于一切!)

我们可以使用 Oracle 自带的 DBMS_REPAIR 包来实现修复。

可参考MOS文档:DBMS_REPAIR SCRIPT (Doc ID 556733.1)

二、实战环境准备

1、环境安装

我使用的一键安装脚本

cd /Volumes/DBA/voracle/github/single_db

vagrant up

vagrant ssh 

Oracle 数据坏块的多种修复方式-1

2、测试数据准备

创建表空间:

create tablespace eason datafile '/oradata/orcl/eason.dbf' size 1g autoextend on; 

Oracle 数据坏块的多种修复方式-2

创建用户:

create user eason identified by eason default tablespace eason; 

grant dba to eason; 

Oracle 数据坏块的多种修复方式-3

创建测试表:

create table hyj as select * from dba_objects; 

Oracle 数据坏块的多种修复方式-4

创建表索引:

create index i_hyj on hyj(object_id); 

Oracle 数据坏块的多种修复方式-5

3、查看表相关信息

查看表段上的相关信息:

select segment_name , header_file , header_block,blocks from dba_segments where segment_name ='HYJ';  

Oracle 数据坏块的多种修复方式-6

查出包含行记录的数据块:

select distinct dbms_rowid.rowid_block_number(rowid) from eason.hyj order by 1;  

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) 

                                 1411

                                 1412

                                 1413

         ...

         ...

         ...

                                  2665

                                 2666

                                 2667

  1232 rows selected. 

Oracle 数据坏块的多种修复方式-7

select * from dba_extents where segment_name='HYJ'; 

Oracle 数据坏块的多种修复方式-8

4、RMAN 备份

首先,我们先做一个全备份,用来演示 RMAN 修复坏块!

run {

allocate channel c1 device type disk;

allocate channel c2 device type disk; 

crosscheck backup; 

crosscheck archivelog all; 

sql"alter system switch logfile"; 

delete noprompt expired backup;

delete noprompt obsolete device type disk;

backup database include current controlfile format '/backup/backlv_%d_%T_%t_%s_%p'; 

backup archivelog all DELETE INPUT; 

release channel c1; 

release channel c2; 

Oracle 数据坏块的多种修复方式-9

5、模拟坏块

破坏 1468、1688、2468 数据块的内容:

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=1468 count=1 

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=1688 count=1 

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=2468 count=1 

Oracle 数据坏块的多种修复方式-10

清除 buffer cache 的内容:

alter system flush buffer_cache; 

Oracle 数据坏块的多种修复方式-11

再次查询表 hyj,此时查询已经报错,发现有坏块:

select * from eason.hyj; 

Oracle 数据坏块的多种修复方式-12 

当然,也可以使用 bbed 进行坏块模拟!

6、坏块检查

下面再介绍几种发现坏块的方式:

(1)使用 DBV 检查当前文件的坏块:

dbv file=/oradata/orcl/eason.dbf blocksize=8192; 

Oracle 数据坏块的多种修复方式-13

使用 DBV检查,同样发现了坏块!

(2)使用 rman 检查数据库坏块:

## 检查对应的数据文件 

backup check logical validate datafile 5; 

## 检查当前数据库 

backup validate check logical database; 

Oracle 数据坏块的多种修复方式-14

结合 V$DATABASE_BLOCK_CORRUPTION 视图查看,更加方便:

select * from V$DATABASE_BLOCK_CORRUPTION; 

Oracle 数据坏块的多种修复方式-15

使用 RMAN 检查后,同样发现了坏块!

(3)通过数据库的告警日志也可以发现报错:

Oracle 数据坏块的多种修复方式-16

(4)通过报错信息快速查找对应的坏表,依次填写数据文件 ID 5 和 坏块 ID 1468:

SELECT tablespace_name, segment_type, owner, segment_name 

FROM dba_extents

         WHERE file_id = &fileid 

and &blockid between block_id AND block_id + blocks - 1; 

Oracle 数据坏块的多种修复方式-17

实验环境准备完毕,下面开始实战!

三、实战演示

今天,我打算使用上述介绍的 2 种方式来演示!

1、RMAN 修复

由于我们之前已经备份了,因此直接使用备份来恢复坏块:

blockrecover datafile 5 block 1468; 

Oracle 数据坏块的多种修复方式-18

blockrecover datafile 5 block 1688,2468; 

Oracle 数据坏块的多种修复方式-19

使用同样的方式,依次修复坏块 1688,2468,修复成功后,查询已恢复正常!

再次检查坏块情况:

backup validate check logical database; 

select * from V$DATABASE_BLOCK_CORRUPTION; 

Oracle 数据坏块的多种修复方式-20

坏块已经都被恢复,并且数据没有丢失!

2、DBMS_REPAIR 修复

首先,依然使用 dd 先模拟坏块:

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=3333 count=1 

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=3368 count=1 

dd if=/dev/zero of=/oradata/orcl/eason.dbf bs=8192 conv=notrunc seek=4000 count=1 

Oracle 数据坏块的多种修复方式-21 

在没有备份的前提下,我们就无法做到无损修复坏块了,需要损失对应坏块的数据。

(1)创建 repair 表,用于记录需要被修复的表:

begin 

dbms_repair.admin_tables (

      table_name => 'REPAIR_TABLE',

      table_type => dbms_repair.repair_table,

      action => dbms_repair.create_action,

      tablespace => 'USERS'); 

end; 

Oracle 数据坏块的多种修复方式-22

(2)创建 Orphan Key 表,用于记录在表块损坏后那些孤立索引,也就是指向坏块的那些索引 :

begin 

dbms_repair.admin_tables (

      table_name => 'ORPHAN_KEY_TABLE',

      table_type => dbms_repair.orphan_table,

      action => dbms_repair.create_action,

      tablespace => 'USERS'); 

end; 

Oracle 数据坏块的多种修复方式-23

(3)检查坏块,检测对象上受损的情形,并返回受损块数为 3:

declare

   num_corrupt int; 

begin

   num_corrupt := 0; 

DBMS_REPAIR.CHECK_OBJECT (

   schema_name =>'EASON',

   object_name =>'HYJ',

   repair_table_name =>'REPAIR_TABLE',

   corrupt_count =>num_corrupt);

   dbms_output.put_line('number corrupt:' || to_char(num_corrupt)); 

end; 

Oracle 数据坏块的多种修复方式-24

(4)查看受损的块信息:

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

Oracle 数据坏块的多种修复方式-25

(5)修复被损坏的数据块,这些被损坏的数据块是在执行了 check_object 之后生成的:

declare

   cc number; 

begin

   dbms_repair.fix_corrupt_blocks(schema_name => 'EASON',

   object_name => 'HYJ',

   fix_count => cc);

   dbms_output.put_line('Number of blocks fixed: ' || to_char(cc)); 

end; 

Oracle 数据坏块的多种修复方式-26

标记了 0 个坏块,说明 CHECK_OBJECT 完成了标记工作。

(6)使用 DUMP_ORPHAN_KEYS 过程将那些指向坏块的索引键值填充到 ORPHAN_KEY_TABLE:

declare

cc number; 

begin   dbms_repair.dump_orphan_keys

   (

      schema_name => 'EASON',

      object_name => 'I_HYJ', 

      object_type => dbms_repair.index_object,

      repair_table_name => 'REPAIR_TABLE',

      orphan_table_name=> 'ORPHAN_KEY_TABLE',

      key_count => cc

   );

   dbms_output.put_line('Number of orphan keys: ' || to_char(cc)); 

end; 

Oracle 数据坏块的多种修复方式-27

表明 202 条记录被损坏丢失!

(7)验证对象是否可以查询,下面的结果显示依旧无法查询:

select count(*) from eason.hyj; 

Oracle 数据坏块的多种修复方式-28

(8)跳过坏块:

BEGIN

   DBMS_REPAIR.SKIP_CORRUPT_BLOCKS (

      SCHEMA_NAME => 'EASON',

      OBJECT_NAME => 'HYJ',

      OBJECT_TYPE => dbms_repair.table_object,

      FLAGS => dbms_repair.skip_flag); 

END; 

Oracle 数据坏块的多种修复方式-29

(9)重建索引:

alter index eason.I_HYJ rebuild; 

Oracle 数据坏块的多种修复方式-30

(10)验证结果

Oracle 数据坏块的多种修复方式-31

至此,表中数据可以顺利被访问!

由于坏块并没有消失,而是被标记跳过,因此还是可以查看坏块:

select * from V$DATABASE_BLOCK_CORRUPTION; 

Oracle 数据坏块的多种修复方式-32

用这种方法可以找回部分数据,也可以找回建了索引的值,但是使用dbv再检查表空间的数据文件时,仍然会显示有损坏的数据块。

这时需要把表的数据全部导出,再重建表或者表空间,然后再把找回的数据导入数据库,推荐用 expdp/impdp 命令做,可以彻底消除 dbv 检查到的坏块。

写在最后

备份大于一切,也是最后的防线,所以请大家一定要做好备份!

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论