在"怎样在windows上用DD配合ultraEdit修改数据"一文中我曾经提到"请注意,我这次测试的结果是:一定要先把上述block的16、 17位清零,同时把15位改成0x04后alert log计算出来的checksum值才是对的,如果你不这样做,可以从alert log看到oracle这里计算出来的checksum值明显不对"。
这个观点是不正确的!
正确的观点是只需要把block的16、 17位清零,那么从alert log就可以看到oracle计算出来的checksum值了,而且这个时候alert log里的checksum值就是这个block被oracle计算出来的正确的checksum值。
因为oracle在alert log里记录的computed block checksum 值实际上是并不是这个block被oracle计算出来的正确的checksum值,而是这个block被oracle计算出来的正确的checksum值与这个block的第16、17位记录的checksum值做异或操作后的值。
当你把一个block的16、17位清零后,因为0与一个值做异或操作后还是等于那个值,所在在将16、17位清零后,这个时候alert log里的checksum值就是这个block被oracle计算出来的正确的checksum值了。
好了,我们来看一个例子:
SQL> select file_name from dba_data_files where tablespace_name='TESTTBS';
FILE_NAME
--------------------------------------------------------------------------------
/dras20/astca/test01.dbf
SQL> create table t1 (id number, c1 char(2000), c2 char(2000), c3 char(2000)) tablespace testtbs;
Table created
SQL> insert into t1 VALUES (1, 'A', 'A', 'A');
1 row inserted
SQL> commit;
Commit complete
SQL> select id,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t1;
ID LOCATION
---------- --------------------------------------------------------------------------------
1 133_10
现在我们先shutdown上述数据库然后用dd把133_10这个block给拷出来:
$ dd if=/dras20/astca/test01.dbf of=/dras20/astca/test01.dd count=1 skip=10 bs=8192
1+0 records in.
1+0 records out.
然后再把test01.dd ftp到本地,然后用ultraEdit将ID为1的那条记录的ID值由1改为2。
可以看到这个block现在在块头记录的checksum值是F9 8F
00000000h: 06 02 00 00 21 40 00
00000010h: F9
现在我们将将ID为1的那条记录的ID值由1改为2,即将C1 02改成C1 03:
00000870h: 00 00 00 00 00 00 00 00 00 00 00 00 00
00000880h:
改完后ftp到AIX上,然后再用dd把上述修改过的block给拷回去,再startup上述数据库:
$ dd if=/dras20/astca/test01.dd of=/dras20/astca/test01.dbf bs=8192 seek=10 count=1 conv=notrunc
1+0 records in.
1+0 records out.
SQL> select * from t1;
select * from t1
ORA-01578: ORACLE data block corrupted (file # 133, block # 10)
ORA-01110: data file 133: '/dras20/astca/test01.dbf'
现在我们去看一下alert log:
Corrupt block relative dba: 0x
Bad check value found during buffer read
Data in bad block -
type: 6 format: 2 rdba: 0x
last change scn: 0x0008.aa09db
consistency value in tail: 0xdb
check value in block header: 0xf
spare1: 0x0, spare2: 0x0, spare3: 0x0
***
Reread of rdba: 0x
从上述alert log里我们可以看出以下两点:
1、块头记录的checksum值是F9
2、oracle当发现checksum值不对的时候会尝试再次读一下该block
好了,我们现在根据F9 8F和01 00来计算出上述block在修改后正确的checksum值:
F9
01 00 = 0000 0001 0000 0000
根据异或算法原理,这里很容易可以看出oracle计算出来的正确的checksum值应该是:
1111 1000 1000 1111,即F8
好了,我们这里如法炮制再改一次上述block的checksum值,即将上述block的checksum值改为F8 8F,然后再startup上述数据库:
SQL> select id,dbms_rowid.rowid_relative_fno(rowid)||'_'||dbms_rowid.rowid_block_number(rowid) location from t1;
ID LOCATION
---------- --------------------------------------------------------------------------------
2 133_10
Leave a comment