Oracle数据库特种恢复技术(四)--实验篇
Oracle数据库特种恢复技术(四)--实验篇
作者:谢浩
Oracle数据库特种恢复技术—原理篇链接:http://www.itpub.net/thread-1507760-1-1.html
oracle数据库特种恢复技术—块内篇链接:http://www.itpub.net/thread-1507766-1-1.html
oracle数据库特种恢复技术—转换篇链接:http://www.itpub.net/thread-1507774-1-1.html
原计划中没有这一章节,但是朋友建议我将整个过程的串联独立出来,因此这一部分用一个实际的例子把前三篇的内容做一个串联。
本次试验使用的数据库版本为11.2.0.2.0且打了最新的psu。之所以使用11g版本的数据库,是因为之前的章节都是在10g的基础上进行试验的,这里使用11g验证一下之前的分析结果在不同版本平台的通用性。
create table XH_TEST
(
DUMMY VARCHAR2(1),
NUM NUMBER,
VCHAR VARCHAR2(4000),
DAT DATE
)
tablespace SYSTEM
pctfree 10
pctused 40
initrans 1
maxtrans 255
建立试验用的表,为方便起见表空间选择system,这样整个试验只用一个数据文件就行了。
关闭数据库,并假设数据库由于故障已经不能启动,现在要在不启动数据库的情况下仅通过表名称“XH_TEST”恢复该表,步骤如下
首先通过控制文件查找数据文件的物理路径,在操作系统中执行:
[root@ABnet-db~]# cd /
[root@ABnet-db/]# find . -name *.ctl
因为11g通过dbca建立的库,默认是没有pfile的,因此通过扩展名搜索oracle控制文件。这里需要注意的是,在安装、部署一个系统时,无论是数据库还是应用系统,最好都按照通用惯例来命名各种文件、变量等资源,这样能在之后的工作中带来极大的便利。将控制文件下载到本地进行分析。这里有一个问题,其实这整篇文章中的相关技术在一年前就都已经摸索清楚了,但是却一直没有找到分析oracle控制文件结构的方法或文档,国外比较权威的社区中也只能找到控制文件头的相关结构介绍,现在只能确定控制文件也是采用数据块的格式进行存储的,因此目前只能采用人工的方式从重获取信息,如果哪位能够不吝提供相关帮助的话,就万分感激了。
使用ue打开控制文件,搜索system关键字,之所以搜索system而不是system01.dbf是因为asm命名的文件中也带有表空间关键字,但不带序号。在实验用的两个库中,10g的控制文件中system表空间的第一个文件的完整文件名存放在0x7cc66的位置,在11g的控制文件中该文件名存放在0x7528a的位置。找到该位置后,向前倒数8个字节的位置的01判断为是该文件的绝对文件号,再向前两字节的04判断为文件类型标识,这就意味着绝对文件号占用了两个字节存储,其最大值为0xffff与oracle声称的最大支持文件数量65534基本相符。从这里也可以领会到另一个事实,即,数据库中一些指标的上限,如最大表数量、最大字段数量、最大文件数量、最大表空间数量等等,这些指标的上限其实都是由存储该指标的某个变量或字段的最大长度决定的。
确定系统表空间第一文件的物理路径后深入观察。这里我编写了一段java程序,用以从指定缓冲区的指定偏移量读出指定数量的字节,并以指定格式返回,也可以使用其他方法做转换。
按前面几部分的分析,首先从该文件的文件头偏移8192+96=8288位置读取4个字节的root dba的值:08 02 40 00,进行字节序转换并转换为二进制并补齐32位为:00000000010000000000001000001000,按dba格式转换为1号文件520号数据块。
进入520号数据块,
1、 读出offset 96位置的4个字节的ktemh.next_ktemh变量的值:00 00 0000。(下一个extent map块的地址)
2、 读出offset 92位置的4个字节的ktemh. count_ktemh变量的值:01 00 0000。(当前segment header block中的extent map的行数)
3、 读出offset 108位置的8个字节:09 02 4000 07 00 00 00,将前4个字节进行字节序转换并转换为二进制并补齐32位为:00000000010000000000001000001001,按dba格式转换为1号文件521号数据块。将后4个字节进行字节序转换并转换为十进制为:7。
从以上结果判断,sys.bootstrap$表的全部数据保存在1号文件521号块开始的连续7个数据块中。1、 进入521号数据块,
2、读出offset 36位置的1个字节的ktbbhict变量的值:01(注1:这里有bbed的一个bug)。
3、计算kdbh结构体的偏移量为:20+24+1*24=68。
4、读出offset 68+1位置的一个字节的kdbhntab变量的值:01,该值表示块内存储的数据行属于一个表。
5、读出offset 68+2位置的两个字节的kdbhnrow变量的值:18 00,该值表示块内共存储24行数据。
6、 计算kdbr数组的偏移量为:68+14+1*4=86。
7、读出offset 86位置的2*24=48字节的kdbr数组,并按照每两个字节一个元素分割:
A3 1F, 1A 1F, 95 1D, CD 1C, 4E 1B, 7A 1A,AD 19, 49 17,
7B 16, B3 15, D6 14, 0A 14, EF 12, 05 12,0E 11, 38 0F,
68 0E, 91 0D, 79 0C, 69 09, 9C 08, 5E 06,8D 05, C6 04
将每个元素进行字节序转换后转换为10进制:8099,7962,7573。。。。省略。。。将每个行偏移量加kdbh结构体的偏移量得出行数据实际物理位置。9、读出一行数据:2C 01 03 033E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30,从第四字节截取三个字节3E64 66,转换为真实数值为:-(101-100)*100^(62-62)=-1。最后9字节:38 2E 30 2E 30 2E 30 2E 30转换为字符串:“8.0.0.0.0”。
10、如果当前行不是第24行,则重复执行步骤8。11、如果当前块不是521号块后的第七个块,则重复执行步骤1。
至此,sys.bootstrap$表的数据已经得以恢复,下一步要通过该表定位并恢复数据字典表。要通过数据字典定位表的物理位置,实际上类似于执行以下sql语句:select a.file#,a.block# from sys.tab$ a,sys.obj$ b where a.obj# =b.obj# and b.name = '*****';因此只要恢复sys.tab$、sys.obj$两个表的数据就能定位任意表的物理位置。
从已经恢复出的sys.bootstrap$表的数据中找到sys.tab$、sys.obj$两表的定义可知,sys.obj$存储在FILE 1BLOCK 240位置,sys.tab$存储在C_OBJ#簇中,C_OBJ#簇存储在FILE 1 BLOCK 296位置。恢复sys.obj$的过程与本章节前面恢复sys.bootstrap$表的过程完全相同,不再赘述。sys.tab$恢复过程如下:
1、 进入1号文件296号块。2、 读出offset 96位置的4个字节的ktemh.next_ktemh变量的值:00 00 0000。
3、 读出offset 92位置的4个字节的ktemh.count_ktemh变量的值: 11 0000 00。
4、 读出offset 108位置的8*17个字节,逐个转换为extent首地址。其中第一个extent位于1号文件145号数据块:
1、 进入145号块。
2、 读出offset 36位置的一个字节的ktbbh.Ktbbhict的值:02。(表示存在两个itl槽)
3、 计算kdbh结构体偏移量为20+24+2*24=92。4、 读出offset:kdbh+1位置的一个字节的kdbh. Kdbhntab的值:06。(表示块内数据属于6个对象)
5、 读出offset:kdbh+14位置的kdbt数组,该数组保函6个元素(表示六个表),每个元素长度为4字节。
6、 读出offset:kdbh+14(kdbh的长度)+24(kdbt数组的长度)位置的kdbr数组。
7、 按kdbr数组中记录的行偏移量加上kdbh的偏移量92,逐行读取行数据。8、 读出一行数据举例举例:
6C 00 14 07 02 C1 06 02 C1 07 02 C1 17 01 80 06
42 4C 4F 43 4B 23 02 C1 03 02 C1 17 01 80 FF FF
02 C1 02 FF FF 02 C1 06 01 80 01 80 01 80 01 80
01 80 0180
第一个字节flag的值6C转换为二进制01101100,表示-CH-FL--,说明该行市一个簇成员对象数据行,并且head piece、first piece、last piece都存储在本行没有行链接现象。
第二个字节00表示行锁信息。
第三个字节14表示改行存储20个字段。
第四个字节07表示该行对应的clusterkey的index信息,这里的07表示该行数据和本块内的key行的第7行对应。
第五个字节的02表示第一个字段占两个字节存储。
第六、七两个字节C1 06是第一个字段的值5。
第八个字节的02表示第二个字段占两个字节存储。
第九、十两个字节C1 07是第二个字段的值6。
第十一个字节的02表示第三个字段占两个字节存储。
第十二、十三两个字节C117是第三个字段的值22。
第十四个字节的01表示第四个字段占一个字节存储。
第十五个字节的80是第四个字段的值0。
第十六个字节的06表示第五个字段占六个字节存储。
第十七至二十二字节的424C 4F 43 4B 23是第五个字段的值“BLOCK#”。
第二十三字节的02表示第六个字段占两个字节存储。
第二十四、二十五字节的C1 03是第六个字段的值2。
第二十六字节的02表示第七个字段占两个字节存储。
第二十七、二十八两个字节C117是第七个字段的值22。
第二十九字节的01表示第八个字段占一个字节存储。
第三十字节的80是第八个字段的值0。
第三十一、三十二字节的FFFF表示第九、十两个字段为null。
第三十三字节的02表示第十一个字段占两个字节存储。
第三十四、三十五两个字节C102是第十一个字段的值1。
第三十六、三十七字节的FFFF表示第十二、十三字段为null。
第三十八个字节的02表示第十四个字段占两个字节存储。
第三十九、四十两个字节C106是第十四个字段的值5。
其后的十二个字节01 8001 80 01 80 01 80 01 80 01 80表示后六个字段的值全部为0。 (注释1)
到这里,sys.c_obj$簇以及其所保函的sys.tab$表已经恢复,sys.obj$表也已经恢复,通过这两个表的数据,已经可以定位XH_TEST表的header block所在的文件号以及位置,之后的工作就是对XH_TEST表进行恢复,恢复过程与恢复sys.obj$表的过程完全相同,不再赘述。
至此,已经成功的在脱离oracle数据库软件的情况下恢复了XH_TEST表的数据,下一步要进一步考虑数据完整性的保障,例如,表有未提交事务时前滚、回滚的完成等细节。
注释1:在这里我有一个问题一直没有找到结果,就是:一个簇中具有相同簇键的不同表的数据行是存储在同一个数据块里的,比如刚刚分析的145号数据块保函了6个表的数据,那么oracle是如何分辨哪一行是属于哪个表的?我一开始分析肯定是记录在某个数据字典里的,但是一直没有找到,而且如果是放在数据字典里的,那么这个数据字典的加载顺序必然要先于sys. tab$因为sys.tab$是sys. bootstrap$里最靠前加载的一个表对象,在它前面加载的都是簇、索引、回滚段等,但是sys.tab$前面没有和簇、表相关的字典加载了。如果哪位能在这个问题上指点一二,一定感激不尽。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9606200/viewspace-745680/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/9606200/viewspace-745680/