7 x 24 在线支持!
Oracle 当一个或多个数据文件丢失时如何从表空间中恢复数据
如果自己搞不定可以找诗檀软件专业ORACLE数据库修复团队成员帮您恢复!
诗檀软件专业数据库修复团队
服务热线 : 13764045638 QQ号:47079569 邮箱:service@parnassusdata.com
目的
-------
本文针对从部分可用的表空间中获取数据,以及以下恢复选项不可用的情况。
. 表空间/数据文件媒体恢复选项失败或不可用。
. 无法替换用户或使用Application操作,由于:
- 最近的export dump不可用
- 使用脚本或通过SQL*Loader无法重新填充表
本文描述的步骤仅适用于字典管理的表空间。
范围 & 应用
-------------------
当无法应用正常备份和恢复场景,需要恢复尽可能多的数据的Oracle 数据库管理员。
在数据库在noarchivelog 模式下运行且属于一个用户表空间的一个或多个数据文件在操作系统级别丢失的情况下,你需要按照本文来操作。
- 或 -
archivelog 数据库没有可用的丢失数据文件的备份或必要的重做。
如果从一个或多个数据文件丢失的部分可用的表空间中恢复数据。
----------------------------------------------------------------------------------------------
对引用(多个)数据文件的对象的任意操作会失败并显示:
ORA-01116: error in opening database file 5
ORA-01110: data file 5: '/u01/oradata/V817/data/users02.dbf'
ORA-27041: unable to open file
在没有drop整个表空间的情况下,无法从表空间中删除eliminate单个丢失文件来解决问题。
但首先我们可以尝试尽可能多得恢复数据。
1. 识别(多个)丢失数据文件的文件号:
SQL> select relative_fno, file_name
from dba_data_files
where tablespace_name = '_tablespace_name_';
RELATIVE_FNO FILE_NAME
-------------- --------------------------------------
4 /u01/oradata/V817/data/users01.dbf
=> 5 /u01/oradata/V817/data/users02.dbf
6 /u01/oradata/V817/data/users03.dbf
2. 在表空间中没有在丢失数据文件中分配extent的对象,可以简单地使用各种方法来重建:
- alter table X move tablespace Y
alter index X rebuild tablespace Y
- table export/import
- create table X as select ...
你需要确定在表空间中哪些数据段没有被分配到丢失数据文件的extent,然后使用上述技巧之一重建它们:
SQL> select distinct owner, segment_name, segment_type
from dba_extents
where tablespace_name = '_tablespace_name_'
and relative_fno NOT IN (file number(s) of missing datafile(s) noted in point 1);
OWNER SEGMENT_NAME SEGMENT_TYPE
------------ -------------------- --------------------
SCOTT DEPT TABLE
SCOTT EMP TABLE
...
3.在丢失的(多个)数据文件中分配了一个或多个extent的表空间对象不能简单地被重建,因为访问它们的尝试都将导致ORA-1116。请注意,在分配到丢失数据文件的extent中的数据都将丢失且无法以任何方式恢复。因此,要恢复在这些数据段的其他数据,可以进行以下操作。
3.1 确定哪些数据段的extent分配到(多个)丢失的数据文件:
SQL> select distinct owner, segment_name, segment_type, partition_name
from dba_extents
where relative_fno IN (file number(s) of missing datafile(s) noted in point 1);
OWNER SEGMENT_NAME SEGMENT_TYPE PARTITION_NAME
------------ -------------------- -------------------- -----------------
SCOTT BONUS TABLE
SCOTT PART_TEST TABLE PARTITION PART_TEST_P2
注意你需要对以上列表中返回的每个对象重复3.2到3.4的步骤。
3.2 然后,我们需要检索这些数据段的extent布局。如果有问题的数据段是reguluar表,那么你需要运行的第一个查询。如果是分区表,那么你需要运行第二个查询:
SQL> select e.segment_name, o.data_object_id, e.relative_fno, e.block_id, e.blocks
from dba_extents e, dba_objects o
where o.owner = e.owner
and o.object_name = e.segment_name
and e.owner = 'SCOTT'
and e.segment_name = 'BONUS'
and e.relative_fno IN (file number(s) of missing datafile(s) noted in point 1)
order by e.relative_fno, o.data_object_id, e.block_id;
SEGMENT_NAME DATA_OBJECT_ID RELATIVE_FNO BLOCK_ID BLOCKS
------------------- -------------- ------------ ---------- ----------
BONUS 24532 5 34 10
BONUS 24532 5 44 10
BONUS 24532 5 54 10
SQL> select e.segment_name, e.partition_name, o.data_object_id, e.relative_fno, e.block_id, e.blocks
from dba_extents e,dba_objects o
where o.owner = e.owner
and o.object_name = e.segment_name
and o.subobject_name = e.partition_name
and e.owner = 'SCOTT'
and e.segment_name = 'PART_TEST'
and e.relative_fno IN (file number(s) of missing datafile(s) noted in point 1)
order by e.relative_fno, o.data_object_id, e.block_id;
SEGMENT_NAME PARTITION_NAME DATA_OBJECT_ID RELATIVE_FNO BLOCK_ID BLOCKS
--------------- ---------------------- -------------- ------------ -------- --------
PART_TEST PART_TEST_P2 30130 5 137 128
PART_TEST PART_TEST_P2 30130 5 265 128
PART_TEST PART_TEST_P2 30130 5 393 128
PART_TEST PART_TEST_P2 30130 5 521 128
3.3 使用以上信息,我们可以创建需要排除的rowid。这可以通过使用DBMS_ROWID.ROWID_CREATE功能来实现:
Specification:
function rowid_create(rowid_type IN number,
object_number IN number,
relative_fno IN number,
block_number IN number,
row_number IN number)
return rowid;
Description:
rowid_type - type (restricted/extended)
object_number - data object number (rowid_object_undefined for restricted)
relative_fno - relative file number
block_number - block number in this file
file_number - file number in this block
使用该对象的最低block_id可以构建rowid的下限:
SQL> select dbms_rowid.rowid_create(1,24532,5,34,0) low_rid from dual;
LOW_RID
------------------
AAAF/UAAFAAAAAiAAA
使用最高block_id + 块数 + 1块,可以构建rowid的上限,因为我们不知道在最后的块中会有多少行:(54 + 10 + 1 = 65)。
SQL> select dbms_rowid.rowid_create(1,24532,5,65,0) high_rid from dual;
HIGH_RID
------------------
AAAF/UAAFAAAABBAAA
3.4 最后,可以使用CREATE TABLE AS SELECT 或/和 INSERT ... SELECT来检索数据而无需访问丢失数据文件中的块:
SQL> create table salvage_bonus as
select /*+ ROWID(A) */ *
from A
where rowid < '_low_rid_';
SQL> insert into salvage_bonus
select /*+ ROWID(A) */ *
from A
where rowid >= '_high_rid_';
4. 在表空间中所有对象被抽取后,drop表空间。
SQL> drop tablespace _tablespace_name_ including contents;
5. Recreate 重建表空间并rebuild将所有对象重建,移到到新的表空间。
请注意如果所有对象已在数据库中重建并移到到另一个表空间中,这个最后步骤就可以跳过。
相关文档
-----------------
Note 61685.1 Extracting Data from a Corrupt Table using ROWID Range Scans in Oracle8/8i