使用dbms_repair修复受损数据块

本文介绍如何利用Oracle提供的dbms_repair包来修复数据库中的受损数据块,包括定位受损对象、创建修复所需的表格、检查并记录损坏详情、标记及跳过坏块、重建表与索引等步骤。

使用dbms_repair修复受损数据块

1、根据在全表扫描中出现的受损数据块的绝对文件号和数据块号的提示确定受损对象:

select segment_name,segment_type,owner,tablespace_name,partition_name

  from dba_extents

  where file_id = &AFN and &BL between block_id and block_id + blocks - 1;

2、使用dbms_repair包创建两个数据表:

   declare

   begin

    dbms_repair.admin_tables(table_name => 'REPAIR_TABLE',

                             table_type => dbms_repair.REPAIR_TABLE,

                             action     => dbms_repair.CREATE_ACTION,

                             tablespace => 'TESTDATA');

   end;

  

   declare

   begin

    dbms_repair.admin_tables(table_type => dbms_repair.ORPHAN_TABLE,

                             action     => dbms_repair.CREATE_ACTION,

                             tablespace => 'TESTDATA');

   end;

3、检查受损对象,并将检查结果存入之前创建的表中:

set serveroutput on;

  declare

    rpr_count int;

  begin

    rpr_count := 0;

    dbms_repair.check_object(schema_name       => 'TEST',

                             object_name       => 'B',

                             repair_table_name => 'REPAIR_TABLE',

                             corrupt_count     => rpr_count);

    dbms_output.put_line('repair count:'||to_char(rpr_count));

  end;

4、查看检查结果:

    select t.object_name,

         t.block_id,

         t.corrupt_type,

         t.marked_corrupt,

         t.corrupt_description,

         t.repair_description

from repair_table t;

5、如果受损数据块还没有被标记为“software corrupt,使用dbms_repair包将受损数据块标记为”software corrupt”

set serveroutput on;

declare

    fix_count int;

  begin

    fix_count := 0;

    dbms_repair.fix_corrupt_blocks(schema_name       => 'TEST',

                                   object_name       => 'B',

                                   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;

6、查看有多少索引项指向了坏块:

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

  

 set serveroutput on;

  declare
    key_count int;
  begin
    key_count :=
0;
    dbms_repair.dump_orphan_keys(schema_name       =>
'TEST',
                                 object_name       =>
'TEST_PK',
                                 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;

 

select index_name,count(1) from orphan_key_table group by index_name;

7、 使用dbms_repair包将受损数据块设置为skip,或使用10231事件,使在全表扫描中屏蔽ora-1578错误:

  begin
    dbms_repair.skip_corrupt_blocks(schema_name =>
'TEST',
                                    object_name =>
'B',
                                    object_type => dbms_repair.TABLE_OBJECT,
                                    flags       => dbms_repair.SKIP_FLAG);
  end;

 

8、  重建表和索引:

使用CTAS方法重建表,或者使用dbms_repair包重建对象的freelists

 declare
 begin
    dbms_repair.rebuild_freelists(schema_name =>
'TEST',
                                  object_name =>
'B',
                                  object_type => dbms_repair.TABLE_OBJECT);

 end;

使用alter index indexname rebuild online命令重建索引

在 Oracle 数据库中,`DBMS_CRYPTO` 包主要用于对 `RAW`、`BLOB`、`CLOB` 等数据类型进行加密和解密操作。虽然 `NUMBER` 类型本身不能直接被 `DBMS_CRYPTO` 处理,但可以通过将其转换为 `RAW` 类型后再进行加密操作。 ### 加密 NUMBER 类型的步骤 1. 将 `NUMBER` 类型的数据转换为 `RAW` 类型。 2. 使用 `DBMS_CRYPTO.ENCRYPT` 对 `RAW` 数据进行加密。 3. 存储或传输加密后的 `RAW` 数据。 4. 在需要时使用 `DBMS_CRYPTO.DECRYPT` 进行解密。 5. 将解密后的 `RAW` 数据转换回 `NUMBER` 类型。 ### 示例代码 以下是一个完整的示例,展示如何对 `NUMBER` 类型的数据进行加密和解密: ```sql -- 创建一个测试表 CREATE TABLE encrypted_numbers ( id NUMBER PRIMARY KEY, raw_data RAW(128), encrypted_data RAW(128) ); -- 定义加密和解密的包 CREATE OR REPLACE PACKAGE pkg_number_crypto AS FUNCTION number_to_raw (p_number IN NUMBER) RETURN RAW; FUNCTION raw_to_number (p_raw IN RAW) RETURN NUMBER; FUNCTION encrypt_number (p_number IN NUMBER, p_key IN VARCHAR2) RETURN RAW; FUNCTION decrypt_number (p_encrypted_data IN RAW, p_key IN VARCHAR2) RETURN NUMBER; END pkg_number_crypto; / CREATE OR REPLACE PACKAGE BODY pkg_number_crypto AS -- 将 NUMBER 转换为 RAW FUNCTION number_to_raw (p_number IN NUMBER) RETURN RAW IS l_raw RAW(100); BEGIN l_raw := UTL_RAW.CAST_FROM_NUMBER(p_number); RETURN l_raw; END; -- 将 RAW 转换回 NUMBER FUNCTION raw_to_number (p_raw IN RAW) RETURN NUMBER IS l_number NUMBER; BEGIN l_number := UTL_RAW.CAST_TO_NUMBER(p_raw); RETURN l_number; END; -- 加密 NUMBER FUNCTION encrypt_number (p_number IN NUMBER, p_key IN VARCHAR2) RETURN RAW IS l_key RAW(32); l_encrypted RAW(128); l_raw_data RAW(100); BEGIN l_key := UTL_I18N.STRING_TO_RAW(p_key, 'AL32UTF8'); l_raw_data := number_to_raw(p_number); l_encrypted := DBMS_CRYPTO.ENCRYPT( src => l_raw_data, typ => DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5, key => l_key ); RETURN l_encrypted; END; -- 解密 NUMBER FUNCTION decrypt_number (p_encrypted_data IN RAW, p_key IN VARCHAR2) RETURN NUMBER IS l_key RAW(32); l_decrypted RAW(100); l_number NUMBER; BEGIN l_key := UTL_I18N.STRING_TO_RAW(p_key, 'AL32UTF8'); l_decrypted := DBMS_CRYPTO.DECRYPT( src => p_encrypted_data, typ => DBMS_CRYPTO.ENCRYPT_AES256 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5, key => l_key ); l_number := raw_to_number(l_decrypted); RETURN l_number; END; END pkg_number_crypto; / ``` #### 插入并加密数据 ```sql DECLARE l_key VARCHAR2(30) := 'mysecretpassword'; l_number NUMBER := 123456789; l_encrypted RAW(128); BEGIN l_encrypted := pkg_number_crypto.encrypt_number(l_number, l_key); INSERT INTO encrypted_numbers (id, raw_data, encrypted_data) VALUES (1, pkg_number_crypto.number_to_raw(l_number), l_encrypted); COMMIT; END; / ``` #### 查询并解密数据 ```sql DECLARE l_key VARCHAR2(30) := 'mysecretpassword'; l_decrypted_number NUMBER; BEGIN SELECT pkg_number_crypto.decrypt_number(encrypted_data, l_key) INTO l_decrypted_number FROM encrypted_numbers WHERE id = 1; DBMS_OUTPUT.PUT_LINE('Decrypted Number: ' || l_decrypted_number); END; / ``` ### 注意事项 - 密钥长度应与所选加密算法匹配(如 AES-256 需要 32 字节的密钥)。 - 加密模式和填充方式需一致,否则解密失败[^1]。 - `UTL_RAW.CAST_FROM_NUMBER` 和 `UTL_RAW.CAST_TO_NUMBER` 用于 `NUMBER` 和 `RAW` 之间的转换[^4]。 - 加密后的数据长度通常会比原始数据长,因此字段长度应适当设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值