使用BBED修复SYSTEM表空间数据文件头

作者简介:庞旭光,现就职于北京海天起点,高级oracle维护工程师,拥有6年电信,政府,银行等行业核心系统oracle数据库运维经验,获得11g ORACLE OCM认证,Redhat Enterprise 7 RHCE认证,擅长oracle数据库方面的故障诊断及问题处理。

概述

本文模拟ORACLE数据库system表空间数据文件头块损坏,在没有备份的情况下,如何使用BBED工具进行修复。

本文的模拟环境中,操作系统为Redhat Enterpris Linux6.5(64位),数据库版本为11.2.0.4,数据文件存放在文件系统下。对于使用裸设备或ASM的场景,只要理解了原理,修复过程基本相同。对于裸设备,需要注意部分操作系统上的文件头偏移量问题,如AIX操作系统;对于ASM需要先将数据文件从ASM磁盘组拷贝至文件系统上,然后再进行修复。

另外,修复system表空间数据文件头块和修复其它常规数据(非临时)表空间数据文件头块的过程只有极少部分不同,其余部分完全相同,对于不同之处在操作过程中会给出提示。

备注:切勿在生产环境模拟。

过程演示

使用dd命令破坏system表空间数据文件头块

确定system表空间数据文件名称

注:我这里system表空间下只有一个数据文件。

使用dd命令破坏文件头块

对于数据文件存放在文件系统上的数据库,在使用dd命令操作时,需要跳过操作系统头块,操作系统头块的大小与表空间的BLOCK_SIZE大小相同,我这里为8K。

数据库停止、启动均报错

此时数据库无法正常shutdown:

只能以abort方式shutdown:

启动数据库也会失败:

提示文件头介质损坏,接下来进行修复。

使用bbed工具修复数据文件头

在数据文件头块中,需要修复的内容共有14项,其位置及作用如下:

数据结构

位置

作用

rdba_kcbh

offset 4

文件头块的rdba地址

kccfhfsz offset 44 文件大小(单位为块)
kccfhfno

offset 52

数据文件号

kcvfhrdb

offset 96

root dba

kcvfhcrs

offset 100

文件创建时的SCN

kcvfhcrt

offset 108

文件创建时间

kcvfhsta

offset 138

文件状态

kcvfhtsn

offset 332

文件所属表空间号

kcvfhtln

offset 336

文件所属表空间名称长度

kcvfhtnm

offset 338

文件所属表空间名称

kcvfhrfn

offset 368

文件相对文件号

kscnbas

offset 484

最后一次检查点SCN

kcvcptim

offset 492

最后一次检查点时间

kcvfhcpc

offset 140

检查点计数

由于我们这里的数据文件头块已经完全损坏,可以先从其它数据文件中拷贝一个正常的数据文件头过来,然后再以此为基础,依次修复上述14个部分。

编译生成bbed文件

1、从10g版本的ORACLE_HOME拷贝bbed编译需要的文件至11g版本ORACLE_HOME:

从其它64位Linux操作系统、10g版本的ORACLE_HOME目录拷贝如下文件至11g版本ORACLE_HOME目录对应位置下:

2、编译生成bbed工具:

3、生成bbed的listfile文件以及参数文件:

将如下命令生成的内容拷贝至:listfile.txt文件中:

listfile.txt文件目录任意,我这里保存在:/home/oracle/bbed_test目录下。

4、创建参数文件:

参数文件内容如下:

参数文件保存为:

5、启动bbed:

拷贝正常的数据文件头

这里我们拷贝undo表空间数据文件的文件头块至system表空间数据文件头。我这里undo表空间下只有一个数据文件:

/u01/app/oracle/oradata/ora11gdb/undotbs01.dbf

1、拷贝以前,先dbv校验一下源数据块:

校验成功,头块没有问题。

2、拷贝文件头块:

校验一下数据块:

校验没有问题,提交:

map一下:

接下来依次修复上文中提到的14项内容。

修改文件头块的rdba地址

对应的数据结构为rdba_kcbh,offset为4。

1、获取文件头块的rdba地址

数据块的rdba地址,可以通过如下方式获取:

另外,通过bbed的提示,也可以获取:

对于little endian,需要将其顺序倒过来,即:01004000。

2、通过bbed修改

修改以前先分别用print和dump命令查看一下当前值:

修改:

提交以前,再查看一下:

没有问题,提交:

修改文件大小

对应的数据结构为,kccfhfsz,offset为44 。

此处数据文件大小的单位为block。

1、获取文件真实大小,以块为单位,并转换为16进制。

先从操作系统层面获取到文件的大小,以字节为单位:

再减去操作系统头块大小、除以块大小(8192),得到以块为单位的大小,最后转换为16进制:

补齐:0001d100 ,由于是little endian,需要反过来:即:00d10100 。

注意:此时不能通过查询v$datafile.bytes来获取数据文件的大小,通过v$datafile.bytes查询到的大小实际上是拷贝过来的数据文件头块所在的数据文件的大小,在我这里即为undo数据文件的大小。另外,对于裸设备需要考虑部分操作系统上(如AIX)裸设备文件头偏移量的问题;对于ASM需要先将文件拷贝至文件系统,然后再通过du等命令获取文件大小,再减去操作系统头块大小,最后才能得到文件的准确大小。

2、修改

修改以前先看下当前大小:

修改:

提交以前,再次查看:

没有问题,提交:

修改数据文件号(file#)

对应的数据结构为:kccfhfno,offset为52。

1、获取数据文件号,并转换为16进制。

根据报错时的提示,就可以直接知道文件号:

也可以通过数据库查询:

2、修改

修改以前先查看一下当前值:

修改:

再次查看:

没有问题,提交:

修改数据文件头的root dba

root dba是根数据块地址,只存在于system表空间中,用于指向数据库启动时需要的、非常重要的bootstrap$表的存放地址。对于非system表空间其值为0。

对应的数据结构为:kcvfhrdb,offset 96。

1、获取root dba,并转换为16进制。

找一个相同版本的数据库,执行下面的查询:

(注:数据库处于非open状态时,x$kcvfh无法访问,所以需要通过其它数据库查询)

结果如下:

从结果中,可以看到只有system表空间下的数据文件的值为非0,其余表空间的值均为0。将其转换为16进制:

补齐:00400208,顺序倒过来:08024000,即:08024000。

对于bootstrap$表,这里简单延伸一下,对于11gR2版本,该数据块为1号文件,520号块:

更多关于bootstrap$表相关的信息,可以自行查询一下,这里不详述。

2、修改

修改以前,先看一下:

修改:

提交以前,再次查看:

没有问题,提交:

对于非system表空间数据文件,root dba为0,一般不用修改,示例如下:

数据文件创建SCN

对应的数据结构为:kcvfh.kcvfhcrs,offset为100。

1、获取文件创建时的SCN,并转换为16进制。

可以通过查询v$datafile获取,v$datafile的内容来自控制文件:

SCN占用6个字节的空间,由SCN_BASE和SCN _WRAP两部分组成。其中SCN BASE占用4个字节,SCN WRAP占用2个字节,SCN与SCN_BASE、SCN_WRAP的关系为:SCN=(SCN_BASE x 4294967296)+(SCN_WRAP)。

将上面我们得到的SCN号7转换为16进制、6字节形式的SCN,即为:00 00 00 00 00 07,再对其进行倒序即为:07 00 00 00 00 00。

2、修改

修改以前,先查看一下当前值:

当前值实际上是undotbs1表空间下的数据文件创建时的SCN。

分别修改SCN_BASE和SCN_WRAP部分:

修改SCN_BASE部分:

修改SCN_WRAP部分:

修改以前,先看一下当前值:

可以看到当前值已经是0000了,也就是说已经不用修改了,但是为了避免在处理其它问题时,忘记修改SCN_WRAP,这里我们也执行一下修改动作:

提交以前查看一下:

没有问题,提交:

数据文件创建时间

对应的数据结构为:kcvfhcrt,offset 为108。

1、获取文件创建时间,并将其转换为16进制:

文件创建时间,可以通过v$datafile.creation_time获取:

将其转换为16进制:

2、修改

修改以前看一下当前值:

修改:

提交前,再次查看:

没有问题,提交:

数据文件状态

对应的数据结构为:kcvfhsta,offset为138 。

先看一下当前的状态:

对于非system表空间,在异常关闭数据库(如shutdown abort)时,数据文件头的状态多为:0x0004 (KCVFHOFZ),而对于system表空间,在异常关闭数据库时,数据文件头的状态为:0x2004 (KCVFHOFZ),当前状态为0x0004,我们需要将其改为0x2004,同样需要倒过来:0420。

修改:

提交以前,查看下:

没有问题,提交:

数据文件表空间号

对应的数据结构为:kcvfhtsn,偏移量为offset 332 。

1、获取表空间号,并转换为16进制。

表空间号可以通过v$datafile的ts#列获取:

2、修改

修改以前,先看一下当前值:

修改:

提交以前,查看一下:

没有问题,提交:

数据文件表空间名称长度

对应的数据结构为:kcvfhtln,位置为offset 336。

1、获取表空间名称长度,并转换为16进制。

2、修改

修改前,查看当前值:

修改:

再次查看:

提交:

数据文件所属表空间名称

对应的数据结构为:kcvfhtnm,位置为offset 338。

1、获取表空间名称,并使用dump函数进行转换。

这里,我们知道损坏的数据文件所属的表空间的名称为SYSTEM,假如不知道表空间名称的话,可以通过v$tablespace的name列获取:

使用dump函数进行转换:

2、修改

修改以前,先查看下当前值:

可以看到当前值为undo表空间的名称。

接下来修改,单次不能修改6个字节的值,所以我们分两次修改:

最后再将:

中的S和1修改掉:

提交前再次查看:

没有问题,提交:

数据文件相对文件号

对应的数据结构为:kcvfhrfn,位置为offset 368。

1、获取文件相对文件号,并转换为16进制。

可以通过查询v$datafile的rfile#列获取,获取到以后,将其转换为16进制:

2、修改:

修改以前查看下当前值:

修改:

再次查看:

没有问题,提交:

数据文件最后一次检查点SCN

对应的数据结构为kcvfhckp中的kscnbas和kscnwrp,位置为offset 484。

1、获取数据文件最后一次检查点SCN,并将其转换为16进制。

数据文件的检查点SCN可以通过v$datafile的checkpoint_change#获取。

转换为16进制:

补齐:00 00 00 13 c8 d5,倒序:d5c813000000。

2、修改

修改以前查看一下当前值:

修改,单次不能修改6个字节,分三次修改:

提交前,再次查看:

没有问题,提交:

数据文件最后一次检查点时间

对应的数据结构为kcvfhckp.kcvcptim,位置为offset 492。

1、获取文件最后一次检查点时间,并转换为16进制。

数据文件最后一次检查点时间,可以通过查询v$datafile的checkpoint_time列获取:

倒序即为:b52f843a。

2、修改

修改以前,查看当前值:

修改:

查看修改后的值:

没有问题,提交:

数据文件检查点计数

对应的数据结构为kcvfhcpc,位置为offset 140。

1、获取文件检查点计数,并转换为16进制。

数据文件的检查点计数(checkpoint count),可以通过v$datafile_header的checkpoint_count列获取。

2、修改

修改以前查看一下当前值:

修改:

提交以前,再次查看:

没有问题,提交:

至此所有需要处理的项,均已处理完成。

校验一下数据块

verify:

没有问题。接下来尝试open数据库。

open数据库

open过程中,提示文件需要介质恢复,recover datafile以后,数据库成功open。

未经允许不得转载:Oracle一体机用户组 » 使用BBED修复SYSTEM表空间数据文件头

相关推荐