
适用范围
- Version >= 11g
- Platform:Linux
问题概述
bootstrap$ 在Oracle数据库中的作用类似于操作系统的引导区,其中包含了数十张关键的基表。其中任何一张基表的数据被删除(执行了delete并commit,随后数据库重启),都可能导致数据库实例启动时抛出ORA-00600或ORA-00704错误而失败。
由于数据库无法启动,闪回等常规恢复操作也无法实施。此时,恢复思路主要有两种:
- 设法恢复被删除的基表数据。
- 使用ODU(Oracle Database Unloader)等工具直接从数据块中抽取业务数据,然后重新建库并导入。
方案对比
- 恢复基表数据:优点是恢复速度相对较快,成功后数据库能直接
OPEN,无需进行数据导出、重建库和导入的复杂流程。缺点是如果故障场景过于复杂,恢复后仍可能遇到其他问题。
- 使用ODU抽取数据:优点是即使数据库完全无法打开,也能最大概率地挽救业务数据。缺点是技术门槛高,恢复周期长。
那么,当数据库无法启动时,我们如何判断是否由bootstrap$基表损坏引起?又该选择哪种恢复方案呢?一个通用的策略是:优先尝试使用工具恢复基表数据;如果能成功恢复并使数据库正常打开,则无需动用ODU。ODU应作为保障数据安全的最后手段。
以下将通过一个模拟tab$基表数据被删除的场景,演示问题的诊断与恢复全过程。
问题现象与诊断
- 模拟故障
首先查询并备份tab$表,然后删除其数据并提交。
-- 查询当前tab$中的数据量
27-OCT-25> select count(*) from tab$;
COUNT(*)
----------
1321
-- 备份基表
27-OCT-25> create table tab$_bak as select * from tab$;
Table created.
-- 删除数据并提交
28-OCT-25> delete from tab$;
1321 rows deleted.
28-OCT-25> commit;
Commit complete.
- 重现故障
重启数据库,观察错误信息。
28-OCT-25> shutdown abort;
ORACLE instance shut down.
28-OCT-25> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2254824 bytes
Variable Size 377489432 bytes
Database Buffers 134217728 bytes
Redo Buffers 7974912 bytes
Database mounted.
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-00704: bootstrap process failure
ORA-00600: internal error code, arguments: [16703], [1403], [20], [], [], [], [], [], [], [], [], []
同时,在Alert日志中也会记录ORA-00704: bootstrap process failure错误。
诊断关键点:如果在数据库OPEN阶段出现ORA-00704: bootstrap process failure报错,基本可以确定是bootstrap$中的基表数据出现了问题。错误参数[16703], [1403], [20]提供了进一步的线索。
- 深度追踪
通过10046事件跟踪数据库启动过程,精确定位问题SQL。
28-OCT-25> startup mount;
ORACLE instance started.
...
Database mounted.
28-OCT-25> oradebug setmypid
Statement processed.
28-OCT-25> oradebug event 10046 trace name context forever, level 4
Statement processed.
28-OCT-25> alter database open;
alter database open
*
ERROR at line 1:
ORA-01092: ORACLE instance terminated. Disconnection forced
ORA-00704: bootstrap process failure
ORA-00704: bootstrap process failure
ORA-00600: internal error code, arguments: [16703], [1403], [20], [], [], [], [], [], [], [], [], []
查看生成的跟踪文件(prod_ora_70891.trc),可以发现关键信息:
PARSING IN CURSOR #...
select rowcnt,blkcnt,empcnt,avgspc,chncnt,avgrln,nvl(degree,1), nvl(instances,1) from tab$ where obj# = :1
...
BIND #0: ... value=20
...
FETCH #...: ... r=0 ...
跟踪日志显示,数据库在OPEN时尝试执行一条查询tab$表的SQL,传入的绑定变量obj#=20,并且没有获取到任何数据(r=0)。这正好对应了错误参数[20]和[1403](ORA-01403: no data found)。因此可以确定,故障原因是obj#=20的记录在tab$表中被删除,导致引导进程失败。
恢复实战:使用工具恢复基表数据
本次恢复采用一款专用工具,其原理是扫描基表对应的数据块,利用BBED工具清除数据块上的“删除标记”。由于被删除的数据实际上仍物理存在于数据块中,清除删除标记即等效于恢复了数据。这里需要区分聚簇表和非聚簇表,因为它们在BBED中的存储格式不同。
- 获取恢复所需的关键参数
在一个同平台、同版本的正常数据库中执行以下查询,收集必要信息。
-- 1. 确认TAB$是否为聚簇表,并获取聚簇名
select cluster_name,table_name from dba_tables where table_name='TAB$';
CLUSTER_NAME TABLE_NAME
------------------------------ ------------------------------
C_OBJ# TAB$ -- TAB$是聚簇表,属于C_OBJ#聚簇
-- 2. 获取聚簇的dataobj# (kdbt参数,-k)
select obj#,dataobj# from obj$ where name = 'C_OBJ#';
OBJ# DATAOBJ#
---------- ----------
2 2
-- 3. 获取TAB$表的数据段头块位置 (blkloc_segment_header参数,-n)
select t1.obj#,t1.name,t2.ts#,t2.file#,t2.block#,t2.tab#
from obj$ t1,tab$ t2
where t1.obj# = t2.obj#
and t1.NAME='TAB$'
and t2.DATAOBJ#=2;
OBJ# NAME TS# FILE# BLOCK# TAB#
---------- ---------- ---------- ---------- ---------- ----------
4 TAB$ 0 1 144 1
-- 得到第一个-n参数:144
-- 4. 获取TAB$表相关索引的信息
select index_name from dba_indexes where table_name = 'TAB$';
INDEX_NAME
------------------------------
I_TAB1
-- 5. 获取索引I_TAB1在bootstrap$中的块位置(用于设置/清除索引删除标记,-n)
select distinct dbms_rowid.rowid_object(rowid) object_id,
dbms_rowid.rowid_relative_fno(rowid) file_id,
dbms_rowid.rowid_block_number(rowid) block_id
from bootstrap$
where obj# in (select obj# from obj$ where name in ('I_TAB1'));
OBJECT_ID FILE_ID BLOCK_ID
---------- ---------- ----------
59 1 523
-- 得到第二个-n参数:523
-- 6. 获取索引I_TAB1的数据段头块位置(用于恢复索引数据块,-n)
select segment_name,header_file,header_block
from dba_segments
where segment_name in ('I_TAB1')
order by 1;
SEGMENT_NAME HEADER_FILE HEADER_BLOCK
-------------------- ----------- ------------
I_TAB1 1 312
-- 得到第三个-n参数:312
- 准备数据文件列表
创建system.cnf文件,列出SYSTEM表空间的数据文件。
-- 查询SYSTEM表空间的数据文件
set lines 120
col name for a100
select file#,name from v$datafile where ts#=0;
-- 输出示例:
-- FILE# NAME
-- ------ --------------------------------------------------
-- 1 /u01/app/oracle/oradata/prod/system01.dbf
-- 创建system.cnf文件
vi system.cnf
# 内容为:文件号 绝对路径
1 /u01/app/oracle/oradata/prod/system01.dbf
- 执行恢复步骤
按照工具的使用逻辑,依次执行以下步骤。工具脚本recovery_basetab.sh的用法概要如下:
-n: 要处理的起始块号(段头块)
-k: 聚簇表的kdbt序号,非聚簇表无需此参数
-s: 数据库块大小(通常为8192)
-i: 索引名称
-d: 对索引操作,1为添加删除标记,0为清除删除标记
-t: 恢复数据类型,1为数据,2为索引
# 1. 清理可能存在的临时文件
rm -f idx_kdbr.loc
# 2. 为TAB$表的索引(I_TAB1)添加删除标记(模拟索引失效状态)
./recovery_basetab.sh -n 523 -s 8192 -i i_tab1 -d 1
# 3. 恢复TAB$表的数据块(聚簇表,需指定-k参数)
./recovery_basetab.sh -n 144 -k 1 -s 8192 -t 1
# 4. 恢复TAB$表的索引块(I_TAB1)
./recovery_basetab.sh -n 312 -s 8192 -t 2
# 5. 清除TAB$表索引(I_TAB1)上的删除标记
./recovery_basetab.sh -n 523 -s 8192 -i i_tab1 -d 0
- 验证恢复结果
完成上述步骤后,尝试重启数据库。
[oracle@test 基表恢复]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Tue Oct 28 10:20:22 2025
Connected to an idle instance.
28-OCT-25> startup
ORACLE instance started.
Total System Global Area 521936896 bytes
Fixed Size 2254824 bytes
Variable Size 377489432 bytes
Database Buffers 134217728 bytes
Redo Buffers 7974912 bytes
Database mounted.
Database opened. -- 数据库成功打开
28-OCT-25> select count(*) from tab$;
COUNT(*)
----------
1321 -- 数据已恢复
同时检查Alert日志,确认无相关错误,数据库完成正常启动和恢复过程。
总结
本文通过一个完整的实验,演示了因bootstrap$基表(以tab$为例)数据被删除导致数据库无法启动的故障现象、诊断方法及恢复流程。关键点在于通过错误信息ORA-00704和跟踪文件定位到具体受损对象,然后利用底层数据块编辑技术,按照“处理索引标记 -> 恢复数据块 -> 恢复索引块 -> 清除索引标记”的顺序进行修复。掌握此方法,可以在类似严重数据库故障发生时,为快速恢复服务提供一种有效途径。对于更复杂的损坏或此方法失效的情况,则需考虑使用ODU进行最终的数据抽取。在执行任何底层恢复操作前,务必对物理文件进行完整备份。