DBMS_REPAIR包使用详解(一)

2014-11-24 17:10:50 · 作者: · 浏览: 0

任何工具都不是万能的,使用这个包的同时会带来数据丢失、表和索引返回数据不一致,完整性约束破坏等其他问题。因此当出现错误时,应当首先从物理备份或逻辑备份恢复,使用dbms_repair只是在没有备份的情况下使用的一种手段,这种方式一般都会造成数据的丢失。



dbms_repair包的工作原理比较简单,是将检查到的坏块标注出来,使随后的dml操作跳过该块,同时,dbms_repair包还提供了用于保存索引中包含的标注为坏块中的键值,以及修复freelist和segment bitmap的过程。


有一点需要注意,dbms_repair包没有进行授权,只有sys用户可以执行。


下面通过一个例子来简要介绍一下dbms_repair包的使用。


一、构造测试环境


首先建立一个测试用表空间,由于需要用UtralEdit打开数据文件修改部分内容来模拟错误,因此数据文件要建的小一些。


SQL> CREATE TABLESPACE TEST DATAFILE 'E:ORACLEORADATATESTTEST.DBF' SIZE 1M
2 EXTENT MANAGEMENT LOCAL AUTOALLOCATE SEGMENT SPACE MANAGEMENT MANUAL;


表空间已创建。


SQL> CREATE TABLE TEST (ID NUMBER, NAME VARCHAR2(30)) TABLESPACE TEST;



表已创建。



SQL> INSERT INTO TEST SELECT ROWNUM, OBJECT_NAME FROM DBA_OBJECTS;



已创建6232行。



SQL> COMMIT;


提交完成。



SQL> CREATE INDEX IND_TEST_ID ON TEST (ID);



索引已创建。



SQL> CREATE INDEX IND_TEST_NAME ON TEST (NAME);



索引已创建。



为了确保oracle已经把刚才插入的数据写到数据文件中,现在重起数据库



SQL> CONN /@TEST AS SYSDBA
已连接。
SQL> SHUTDOWN
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。



Total System Global Area 89201304 bytes
Fixed Size 453272 bytes
Variable Size 62914560 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
数据库装载完毕。
数据库已经打开。





二、模拟错误的产生


用UtralEdit打开数据文件,只要修改了数据文件中任意的一个位置,都会造成数据文件错误。但我们测试需要将错误发生位置定位在TEST表中。



SQL> CONN YANGTK/YANGTK@TEST
已连接。



SQL> SELECT SUBSTR(ROWID, 10, 6), ID, NAME FROM TEST WHERE ID = 123;



SUBSTR(ROWID ID NAME
------------ ---------- ------------------------------
AAAAAG 123 ALL_REPCONFLICT



如何在数据文件中找到TEST表的数据呢?可以通过ROWID来定位的记录在数据文件中的位置。任意选择一条记录(如上面ID = 123),取得它的ROWID,我们知道,ROWID中10~15位表示这条记录所在的BLOCK是数据文件的第几个BLOCK。



A表示0,B为1,G表示6。这说明这条记录在数据文件的第六个block中。



SQL> SHOW PARAMETER DB_BLOCK_SIZE



NAME TYPE VALUE
------------------------------------ ----------- ---------------
db_block_size integer 16384



BLOCK的大小是16k。



SQL> SELECT TO_CHAR(6*16384, 'XXXXXX') FROM DUAL;



TO_CHAR
-------
18000



SQL> SELECT TO_CHAR(7*16384, 'XXXXXX') FROM DUAL;



TO_CHAR
-------
1C000



用UtralEdit打开数据文件,将文件定位18000h处(以二进制方式打开,如果没有用二进制打开,可以使用CTRL+H快捷键切换)。根据上面的计算,可以得出,我们要找到记录在18000h和1C000h之间。



Number类型123在数据库存放方式为03C20218,03表示占有三位,C2表示最高位是百位,02表示最高位上是1,18表示低位上是23。



具体的数值可以通过下面的查询得到:



SQL> SELECT DUMP(123) FROM DUAL;



DUMP(123)
---------------------
Typ=2 Len=3: 194,2,24



SQL> SELECT TO_CHAR(194, 'XX'), TO_CHAR(2, 'XX'), TO_CHAR(24, 'XX') FROM DUAL;



TO_ TO_ TO_
--- --- ---
C2 2 18



关于具体的NUMBER类型在数据库中是如何存储的,有兴趣的可以参阅另一篇文章。



下面使用UtralEdit的搜索功能,查找到03C20218,将其修改为03C20216,并保存。



上面是通过oracle的ROWID在文件中定位,这相对来说要复杂一些。下面可以使用UtralEdit的功能达到相同的目的。



根据上面的查询可以得到,ID = 123时,NAME的值是ALL_REPCONFLICT。



下面用UtralEdit打开文件,使用CTRL+H方式切换到文本格式,直接查找ALL_REPCONFLICT字符串。找到后,CTRL+H切换回二进制格式。向前跳过一个长度字节(本例中为0F),就可以看到123的值03C20218,进行修改后,保存并退出。



SQL> SELECT * FROM TEST WHERE ID = 123;



ID NAME
---------- ------------------------------
123 ALL_REPCONFLICT



这时候查询仍然可以得到正确结果,因为oracle使用了db_cache中的结果。为了让oracle“看”到修改,必须重起数据库。



SQL> CONN /@TEST AS SYSDBA
已连接。
SQL> SHUTDOWN
数据库已经关闭。
已经卸载数据库。
ORACLE 例程已经关闭。
SQL> STARTUP
ORACLE 例程已经启动。



Total System Global Area 89201304 bytes
Fixed Size 453272 bytes
Variable Size 62914560 bytes
Database Buffers 25165824 bytes
Redo Buffers 667648 bytes
数据库装载完毕。
数据库已经打开。
SQL> CONN YANGTK/YANGTK@TEST
已连接。



SQL> SELECT * FROM TEST WHERE ID = 123;
SELECT * FROM TEST WHERE ID = 123