使用DBMS_REPAIR包修复坏块(二)
昨天简单得了解了一下关于数据块损坏后该如何操作,都是一些理论知识,当然理论知识也还没有学完
。今天来继续学习理论知识,并且在完成之后找一个实例来实践一下。好,下面开始。
--------------------------------------
二、评估使用DBMS_REPAIR的损益
要判断损益,需要了解一下问题:
1、损坏的盘区是什么?
这一步比较简单,执行CHECK_OBJECT过程,然后查询修复表即可。
2、其他可用于处理数据损坏的方法是什么?
需要考虑以下几种方法:
* 假设可以从另一数据源获得数据,则删除、重建、并填充该对象。
* 对损坏的表发布CREATE TABLE ... AS SELECT语句,以重建新表
* 通过从选取(select)语句来排除损坏的行来忽略损坏
* 执行介质恢复
3、当使用DBMS_REPAIR来使一个对象可用时,会引入什么逻辑矛盾或副作用?并考虑代价
主要可能会有以下问题:
* 标记损坏的数据块中的行会无法访问。
* 有可能破坏参照完整性约束,如有则需要停用
* 如果在表上定义了触发器,要考虑如果删除、重新插入数据是否会触发
* 空闲列表数据块可能不可访问。
如果损坏数据块在空闲列表的头部或尾部,则空间管理会重新初始化该空闲列表。
可能会存在该放入空闲列表但有没有放入的数据块,运行REBUILD_FREELISTS解决这个问题。
* 索引和表不同步了。需要执行DUMP_ORPHAN_KEYS获得信息,然后用ALTER INDEX ... REBUILD ONLINE同步
4、如果修复中丢失了数据,这些数据还能被检索码?
当数据库被标记为损坏时,仍可以从索引中检索数据。DUMP_ORPHAN_KEYS过程可以有助于检索该信息。当然这种方法检索数据取决于索引和表之间数据冗余的数量。
三、使对象可用
1、损坏修复(使用FIX_CORRUPT_BLOCKS和SKIP_CORRUPT_BLOCKS)
通过建立一个环境,跳过DBMS_REPAIR修复能力范围之外的损坏,使损坏对象可用。如果该损坏包括了数据丢失,如数据块中的坏行,所有这样的数据块都被FIX_CORRUPT_BLOCKS过程标记为损坏。然后运行SKIP_CORRUPT_BLOCKS跳过对象中被标记为损坏的数据块。当设置跳过后,表和索引扫描就跳过所有被标记成损坏的数据块,这适用于介质和软件损坏数据块两者。
2、跳过损坏数据块时的意义
如果索引和表不同步了,那么当一个查询仅仅探查索引,而下一个查询探查索引和表两者时,SET TRANSACTION READ ONLY事务就可能有矛盾。如果表数据块被标记成损坏,那么两个查询就会返回不同的结果,这就破坏了只读事务的规则。
处理这个问题的一个方法是在SET TRANSACTION READ ONLY事务中不跳过损坏数据块。当选取被链接在一起的行时也会发生相同的问题,本质上说,对相同行的查询既可以又不可以访问损坏数据块,因此产生不同结果
四、修复损坏和重建丢失的数据
1、用DUMP_ORPHAN_KEYS过程恢复数据
DUMP_ORPHAN_KEYS过程报告指向损坏数据块中的行的索引项。所有这些索引项都被插入到一个孤立键表中,该表存储了损坏数据块的键和行标识。索引出了索引项信息之后,就可以使用ALTER INDEX ... REBUILD ONLINE语句重建该索引。
2、用REBUILD_FREELISTS过程修复空闲列表
如果是空闲列表(SEGMENT SPACE MANAGEMENT MANUAL)来管理段中的空闲空间时,就使用该过程。
当在空闲列表的头部或尾部找到了被标记为“损坏”的数据块时,将重新初始化空闲列表,并返回一个错误。这样虽然从空闲列表中清除了错误数据块,但是它使得空闲列表不能访问紧跟损坏数据块之后的所有数据块,此时可以使用REBUILD_FREELISTS过程来重新初始化空闲列表。
此时对象会被扫描,若适合作为空闲列表上的数据块,则增加到这里面。
3、用SEGMENT_FIX_STATUS过程修复段位图
对于用位图(SEGMENT SPACE MANAGEMENT AUTO)来管理段中的空闲空间时,使用这个过程。这个过程或者基于对应的数据块的当前内容重新计算位图的状态,或者指定将位图项设置成特殊的值。通常,状态被正确得中心计算而不需要强行设置。
五、示例
---------------------------------------------
-- 首先用ADMIN_TABLES建立修复表/孤立键表
-- 修复表用于表示错误数据块以及修复方法
-- 修复表 -> FIX_CORRUPT_BLOCKS
-- 孤立键表 -> DUMP_ORPHAN_KEYS
---------------------------------------------
--先来建立修复表
begin
dbms_repair.admin_tables(table_name => 'REPAIR_WXQ',
table_type => dbms_repair.repair_table,
action => dbms_repair.create_action,
tablespace => 'WXQ_TBS2');
end;
/
--查看一下
SQL> desc REPAIR_WXQ
Name Type Nullable Default Comments
------------------- -------------- -------- ------- --------
OBJECT_ID NUMBER
TABLESPACE_ID NUMBER
RELATIVE_FILE_ID NUMBER
BLOCK_ID NUMBER
CORRUPT_TYPE NUMBER
SCHEMA_NAME VARCHAR2(30)
OBJECT_NAME VARCHAR2(30)
BASEOBJECT_NAME VARCHAR2(30) Y
PARTITION_NAME VARCHAR2(30) Y
CORRUPT_DESCRIPTION VARCHAR2(2000) Y
REPAIR_DESCRIPTION VARCHAR2(200) Y
MARKED_CORRUPT VARCHAR2(10)
CHECK_TIMESTAMP DATE
FIX_TIMESTAMP DATE Y
REFORMAT_TIMESTAMP DATE Y
-- 用同样的过程创建孤立键表
begin
dbms_repair.admin_tables(table_name => 'ORPHAN_WXQ',
table_type => dbms_repair.orphan_table,
action => dbms_repair.create_action,
tablespace => 'WXQ_TBS2');
end;
/
--同样来查看一下表结构
SQL> desc ORPHAN_WXQ
Name Type Nullable Default Comments
-------------- ------------ -------- ------- --------
SCHEMA_NAME VARCHAR2(30)
INDEX_NAME VARCHAR2(30)
IPART_NAME VARCHAR2(30) Y
INDEX_ID NUMBER
TABLE_NAME VARCHAR2(30)
PART_NAME VARCHAR2(30) Y
TABLE_ID NUMBER
KEYROWID UROWID(4000)
KEY UROWID(4000)
DUMP_TIMESTAMP DATE
---------------------------------------------
-- 接着用CHECK_OBJECT来检查损坏数量
-- 注意:最终输出为一个int型数字
---------------------------------------------
declare
num_corrupt int := 0;
begin
dbms_repair.check_object(schema_name => 'WANGXIAOQI',
object_name => 'T1',
repair_table_name => 'REPAIR_WXQ',
corrupt_count => num_corrupt);
dbms_output.put_line('number corrupt: ' || to_char(num_corrupt));
end;
/
-- 查看修复表
select a.object_name,
a.block_id,
a.corrupt_type,
a.marked_corrupt,
a.corrupt_description,
a.repair_description
from repair_wxq a;
OBJECT_NAME BLOCK_ID CORRUPT_TYPE MARKED_COR CORRUPT_DESCRIPTION REPAIR_DESCRIPTION
----------- -------- ------------ ---------- ------------------- ------------------
T1 3 1 FALSE .... ....
---------------------------------------------
-- 使用FIX_CORRUPT_BLOCKS来修理损坏数据块
--
---------------------------------------------
declare
num_fix int := 0;
begin
dbms_repair.fix_corrupt_blocks(schema_name => 'WANGXIAOQI',
object_name => 'T1',
object_type => dbms_repair.table_object,
repair_table_name => 'REPAIR_WXQ',
fix_count => num_fix);
dbms_output.put_line('num fix: ' || to_char(num_fix));
end;
/
--确认已做修复
select a.object_name, a.block_id, a.marked_corrupt
from repair_wxq a;
OBJECT_NAME BLOCK_ID MARKED_COR
----------- -------- ----------
T1 3 FALSE
----------------------------------------------------
-- 使用DUMP_ORPHAN_KEYS来查找指向损坏数据块的指引项
--
----------------------------------------------------
declare
num_orphans int := 0;
begin
dbms_repair.dump_orphan_keys(schema_name => 'WANGXIAOQI',
object_name => 'T1_PK',
object_type => dbms_repair.index_object,
repair_table_name => 'REPAIR_WXQ',
orphan_table_name => 'ORPHAN_WXQ',
key_count => num_orphans);
dbms_output.put_line('orphan key count: ' || to_char(num_orphans));
end;
/
---------------------------------------------
-- 使用REBUILD_FREELISTS重建空闲列表
--
---------------------------------------------
begin
dbms_repair.rebuild_freelists(schema_name => 'WANGXIAOQI',
object_name => 'T1',
object_type => dbms_repair.table_object);
end;
/
---------------------------------------------
-- 使用SKIP_CORRUPT_BLOCKS控制是否跳过坏块
--
---------------------------------------------
begin
dbms_repair.skip_corrupt_blocks(schema_name => 'WANGXIAOQI',
object_name => 'T1',
object_type => dbms_repair.table_object,
flags => dbms_repair.SKIP_FLAG);
end;
/
--查看该表状态
select owner, table_name, skip_corrupt
from dba_tables
where table_name = 'T1';