yuyulu
作者yuyulu·2011-02-15 10:32
系统工程师·自由职业

转:数据恢复工具(老熊odu)实验

字数 33337阅读 11193评论 0赞 1

数据恢复工具odu实验

odu安装

本次实验技术资料源自老熊的BLOG http://www.laoxiong.net
ODU软件可去老熊的BLOG下载http://www.laoxiong.net/odu
根据操作系统选择不同的版本:
Windows版本:odu_309_win32.zip (770KB) 
Linux版本:odu_308_linux_x86.tar.gz (1064KB) 
Solaris版本:odu_306_sol_x86.tar.gz (766KB) 
AIX版本:odu_308_aix53.tar.gz (1344KB) 
HP PA-RISC2.0版本:odu_308_hppa.tar.gz (926KB) 
HP IA64版本:odu_308_hp_ia64.tar.gz (896KB)
本次实验使用 Linux版本:odu_308_linux_x86.tar.gz (1064KB)
 

1、登录LINUX操作系统,使用MYGET下载到/opt/soft目录,注意下载用户对/opt/soft目录是否有写权限,否则myget会报错Can not
open the temp file to write: Permission denied
mytget -d /opt/soft http://www.laoxiong.net/odusoft/odu_308_linux_x86.tar.gz
 
2、解压缩到/opt目录下
tar -zxvf odu_308_linux_x86.tar.gz -C /opt
 
3、确认安装完成
[oracle@dns1 odu]$ ls
config.txt  control.txt  data  odu
data目录用于存放恢复后的数据文件
config.txt  是odu的配置文件
control.txt 是odu的控制文件,存放的是需要回复的数据库文件信息
 
odu实验
 
1、确认实验目的
  (1)odu配置
  (2)启动ODU
  (3)恢复delete的数据
  (4)恢复drop purge的表
  (5)恢复truncate的表
  (6)复杂情况的表恢复
 
2、实验内容


(1)odu配置


      a) 第一步是修改配置文件config.txt,首先看下文件的默认设置
byte_order little     
/*数据文件平台字节序,跟数据文件运行平台有关,和运行ODU的平台无关。unix操作系统大部分是big,X86机器是little,数据库

装在X86的linux上,所以这里无需修改。
 big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C
写在前面,还是将49写在前 面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。 
*/
block_size  8192     
/*数据库文件的块大小,装ORACLE的时候选的是默认块大小8192,这里也无需修改。
查看方式SQL> show parameter db_block_size  或  select name,value from v$parameter where name='db_block_size';   */
db_timezone -7     
/*数据库时区  无需修改*/
client_timezone 8     
/*客户端时区 中国是正8  无需修改,除非不在中国用ODU*/
data_path   data     
/*恢复数据的存放目录  如果恢复的数据库过大,请将该目录指向一个大存储空间。目录必须已存在,绝对路径相对路径都可以*/
charset_name ZHS16GBK     
/*数据库字符集  对应数据库里的NLS_CHARACTERSET
ODU目前不支持所有的字集值,主要包括US7ASCII、ZHS16GBK、UTF8、AL16UTF16、ZHS16CGB231280这五种,下同
 select * from nls_database_parameters where parameter in ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');
*/
ncharset_name AL16UTF16     
/*数据库国家字符集   对应数据库里的NLS_NCHAR_CHARACTERSET*/
output_format text     
/*输出文件格式 txt或是dmp ,txt类型用sqlldr工具导入数据库*/
lob_storage infile     
/*大对象存放方式,infile是和其他类型字段存放在同一个文件中,如要手动设置,必须是绝对路径*/
clob_byte_order little     
/*CLOB字段的平台字节序 10G数据库 默认是big*/
SQL>  show parameter db_block_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192
SQL> select * from nls_database_parameters where parameter in ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');
PARAMETER
------------------------------
VALUE
--------------------------------------------------------------------------------
NLS_CHARACTERSET
AL32UTF8
NLS_NCHAR_CHARACTERSET
AL16UTF16

经过系统检查,本次试验需要修改4个参数charset_name,ncharset_name,unload_deleted,clob_byte_order 。UNLOAD_DELETED为
是否恢复delete的数据,第一个试验需要启用。clob_byte_order 参数对于clob字段的恢复很重要,如果修改不正确会导致clob数据全是乱码。
在config.txt文件中修改或添加
   
charset_name     AL32UTF8
ncharset_name    AL16UTF16
unload_deleted   yes
clob_byte_order  big
odu配置控制文件control.txt
   控制文件默认是5列#ts #fno   #rfno     filename      block_size,可以只需要前四列,即块大小和是否大文件表空间可省
略。
   完整的控制文件总共有以下几列内容:表空间号、文件号、相对文件号、文件名、块大小、是否大文件表空间。
   ODU将检查control.txt文件中的第一个数据文件是否为SYSTEM表空间文件,所以要将SYSTEM表空间的第1个文件放在control.txt
文件中的第一行。否则将不能自动获得数据字典数据。
   可用以下SQL查询控制文件的4个参数:
   select ts#,file#,rfile#,name,block1_offset From v$datafile;
   本次实验用到的表位于users表空间,因此只填写了system和users两个表。
   用SQL> host vi opt/odu/control.txt命令修改控制文件成如下:
   #ts #fno   #rfno     filename
   0   1      1         /database/app/oracle/oradata/orcl/system01.dbf
   4   4      4         /database/app/oracle/oradata/orcl/users01.dbf
 

(2)启动ODU

[oracle@dns1 odu]$ ./odu
Oracle Data Unloader:Release 3.0.8
Copyright (c) 2008,2009 XiongJun. All rights reserved.
loading default config.......
byte_order little
block_size  8192
db_timezone -7
client_timezone 8
data_path   data
output_format text
lob_storage infile
clob_byte_order little
charset_name    AL32UTF8
charset name 'AL32UTF8' not found,will use default charset ZHS16GBK
ncharset_name   AL16UTF16
unload_deleted  yes
load control file 'config.txt' successful
loading default control file ......

 ts#   fn  rfn bsize   blocks bf offset filename
---- ---- ---- ----- -------- -- ------ --------------------------------------------
   0    1    1  8192    62720 N       0 /database/app/oracle/oradata/orcl/system01.dbf
   4    4    4  8192      640 N       0 /database/app/oracle/oradata/orcl/users01.dbf
load control file 'control.txt' successful
loading dictionary data......
可以看见有一行报错,AL32UTF8不是系统能识别的字符集,系统默认用ZHS16GBK替换。ODU目前不支持所有的字集值,主要包括
US7ASCII、ZHS16GBK、UTF8、AL16UTF16、ZHS16CGB231280这五种。
控制文件读取正常,2个数据文件都已设置好了。ODU启动时自动读取参数和控制文件,或者用load config 和open命令手动读取。
 

(3)恢复delete的数据

<a>首先确认数据,模拟删除操作。
SQL> desc test1 
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 C                                                  NUMBER(38)
 D                                                  VARCHAR2(20)
QL> select * from test1;
         C D
---------- --------------------
         1 111
         2 222
         3 333
         4 444
SQL> delete from test1;
4 rows deleted.
SQL> commit;
Commit complete.
<b> 切换到SYS用户,确认表所在表空间,并将表空间脱机。
SQL> select TABLESPACE_NAME from dba_tables where OWNER='MWZ' and TABLE_NAME='TEST1';              
TABLESPACE_NAME
------------------------------
USERS
SQL> alter tablespace users offline;
Tablespace altered.
<c> 启动odu,从SYSTEM表空间中导出数据字典,并存储在.odu文件中。下次打开odu时,odu会自动从生成的文件中装入数据字典。
ODU> unload dict
ODU> unload table mwz.test1
Unloading table: TEST1,object ID: 52594
Unloading segment,storage(Obj#=52594 DataObj#=52594 TS#=4 File#=4 Block#=403 Cluster=0)
4 rows unloaded
因为表没有被删除,数据字典里能直接找到相关信息,比如object ID,因此恢复操作很简单。提示结果4行记录成功恢复。
<d>进入data目录确认数据:(启动ODU的时候,可直接用host命令切换到系统shell中)
[oracle@dns1 data]$ ls
MWZ_TEST1.ctl  MWZ_TEST1.sql  MWZ_TEST1.txt
[oracle@dns1 data]$ more MWZ_TEST1.ctl
--
--Generated by ODU,for table "MWZ"."TEST1"
--
OPTIONS(BINDSIZE=8388608,READSIZE=8388608,ERRORS=-1,ROWS=50000)
LOAD DATA
INFILE 'MWZ_TEST1.txt' "STR X'0a'"
APPEND INTO TABLE "MWZ"."TEST1"
FIELDS TERMINATED BY X'7c' TRAILING NULLCOLS
(
    "C" ,
    "D" CHAR(20)
)
[oracle@dns1 data]$ more MWZ_TEST1.sql
CREATE TABLE "MWZ"."TEST1"
(
    "C" NUMBER ,
    "D" VARCHAR2(20) 
);
[oracle@dns1 data]$ more MWZ_TEST1.txt
1|111
2|222
3|333
4|444
data目录中有3个文件MWZ_TEST1.ctl、MWZ_TEST1.sql、MWZ_TEST1.txt。
MWZ_TEST1.sql是恢复出来的表结构
MWZ_TEST1.txt是数据内容,字段分隔符可在控制文件中自由设置
MWZ_TEST1.ctl是sqlldr工具的控制文件,用来读取MWZ_TEST1.txt文件内容。
<e>恢复数据
首先将users表空间上线
SQL> alter tablespace users online;
Tablespace altered.
然后切换到操作系统shell,通过sqlldr导入数据。
[oracle@dns1 data]$ sqlldr mwz/password@orcl control=MWZ_TEST1.ctl
SQL*Loader: Release 10.2.0.1.0 - Production on Tue Jun 1 11:25:33 2010
Copyright (c) 1982, 2005, Oracle.  All rights reserved.
Commit point reached - logical record count 4
回到SQLPLUS 确认数据
QL> select * from test1;
         C D
---------- --------------------
         1 111
         2 222
         3 333
         4 444
 
 
 
(4)恢复drop purge的表

<a>模拟操作,表空间离线
SQL> drop table test1 purge;
SQL> alter tablespace users offline;
<b>从redo log中找回被删除表的object id。表从回收箱里purge后,无法用flashback table test1 to before drop恢复,并且原
数据已从数据字典里删除。因此ODU无法读取表的原始数据(主要是object id),因此必须从redo log中查找相关资料。redo log中
的undo_sql会记录删除原数据的操作,从中可以找到对应的OBJECT ID.
首先找到当前的日志组
SQL>  select group#,status from v$log;
    GROUP# STATUS
---------- ----------------
         1 CURRENT
         2 INACTIVE
         3 INACTIVE
SQL> select member from v$logfile where group# = 1;
MEMBER
--------------------------------------------------------------------------------
/database/app/oracle/oradata/orcl/redo01.log
使用logmnr挖掘日志。想要找到被删除对象的object id,必须找到系统删除数据字典的语句。这里可以通过以下方法来查找:先找到
我们执行的drop table test1 purge 语句的执行时间,查这个时间点所有执行的SQL,然后自行判断一下。因为需要根据时间点来查
,所以得把日期格式精确到秒,业务特别繁重的系统,可以把查找范围扩大到这个时间点前后几秒。
SQL>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss' ;
SQL> exec sys.dbms_logmnr.add_logfile(logfilename=>'/database/app/oracle/oradata/orcl/redo01.log');
PL/SQL procedure successfully completed.
SQL> exec sys.dbms_logmnr.start_logmnr(options=>sys.dbms_logmnr.dict_from_online_catalog);
PL/SQL procedure successfully completed.
查询logmnr的v$logmnr_contents视图
SQL> select scn,timestamp,sql_redo from v$logmnr_contents where operation='DDL' and sql_redo like '%test1%' order by
2 ;
scn     timestamp               sql_redo  
674364 2010-06-01 11:07:23 drop table test1 AS "BIN$h/BFvHxAzHfgQCAKRgEU5A==$0" ;
674397 2010-06-01 11:07:58 create table test1 (c int,d varchar2(20));
680444 2010-06-01 14:02:48 drop table test1 purge;

SQL> select scn,timestamp,sql_redo from v$logmnr_contents where timestamp=to_date('2010-06-01 14:02:48','yyyy-mm-dd
hh24:mi:ss') order by 1;
"SCN"   "TIMESTAMP"             "SQL_REDO"
680449  2010-06-01 14:02:48     "delete from ""SYS"".""OBJ$"" where ""OBJ#"" = '52594' and ""DATAOBJ#"" = '52594'
and ""OWNER
#"" = '61' and ""NAME"" = 'TEST1' and ""NAMESPACE"" = '1' and ""SUBNAME"" IS NULL and ""TYPE#"" = '2' and ""CTIME""
= TO_DATE
('2010-06-01 11:07:58', 'yyyy-mm-dd hh24:mi:ss') and ""MTIME"" = TO_DATE('2010-06-01 11:07:58', 'yyyy-mm-dd
hh24:mi:ss') and 
""STIME"" = TO_DATE('2010-06-01 11:07:58', 'yyyy-mm-dd hh24:mi:ss') and ""STATUS"" = '1' and ""REMOTEOWNER"" IS NULL
and ""LI
NKNAME"" IS NULL and ""FLAGS"" = '0' and ""OID$"" IS NULL and ""SPARE1"" = '6' and ""SPARE2"" = '1' and ""SPARE3""
IS NULL an
d ""SPARE4"" IS NULL and ""SPARE5"" IS NULL and ""SPARE6"" IS NULL and ROWID = 'AAAAASAABAAAMRrAA1';"
 
exec sys.dbms_logmnr.end_logmnr;
通过  ""OBJ#"" = '52594' and ""DATAOBJ#"" = '52594' 可以判断出test1的object id为52594
<c>使用ODU恢复表
还记得前一个实验中,最后恢复出的三个文件吗?其中.sql文件保存的是表结构,但是test1的原数据已经从数据字典中删除了,因
此需要用odu直接扫描数据文件中的信息,然后读取指定对象ID的数据结构。
ODU> scan extent tablespace 4;
scan extent start: 2010-06-01 15:15:47
scanning extent...
scanning extent finished.
scan extent completed: 2010-06-01 15:15:47
ODU> unload object 52594 sample
Unloading Object,object ID: 52594,  Cluster: 0
output data is in file :  'data/ODU_0000052594.txt'
Sample result:
  object id: 52594
  tablespace no: 4
  sampled 8 rows
  column count: 2
  column    1  type: NUMBER
  column    2  type: VARCHAR2
COMMAND: 
unload object 52594 tablespace 4 column NUMBER VARCHAR2
根据执行结果可以发现,ODU直接把object  52594的表结构、数据行数、列数以及列类型扫描出来了。
执行恢复
ODU> unload object 52594 tablespace 4 column NUMBER VARCHAR2
Unloading Object,object ID: 52594,  Cluster: 0
8 rows unloaded
确认一下导出的数据文件,发现不经过数字字典的恢复会多出一个文件sample.txt,就是ODU> unload object 52594 sample命令的
结果。其他三个文件是系统根据object id自动命名的.
继续查看三个用于恢复数据的文件,会发现执行恢复前有些东西需要手动改动下。
[oracle@dns1 data]$ ls
MWZ_TEST1.ctl  MWZ_TEST1.sql  ODU_0000052594.ctl  ODU_0000052594.txt
MWZ_TEST1.log  MWZ_TEST1.txt  ODU_0000052594.sql  sample.txt
[oracle@dns1 data]$ more ODU_0000052594.ctl
--
--Generated by ODU,for table ""."ODU_0000052594"
--
OPTIONS(BINDSIZE=8388608,READSIZE=8388608,ERRORS=-1,ROWS=50000)
LOAD DATA
INFILE 'ODU_0000052594.txt' "STR X'0a'"
APPEND INTO TABLE "ODU_0000052594"
FIELDS TERMINATED BY X'7c' TRAILING NULLCOLS
(
    "C0001" ,
    "C0002" CHAR(4000)
)
[oracle@dns1 data]$ more ODU_0000052594.sql
CREATE TABLE "ODU_0000052594"
(
    "C0001" NUMBER ,
    "C0002" VARCHAR2(4000) 
);
[oracle@dns1 data]$ more ODU_0000052594.txt
1|111
2|222
3|333
4|444
1|111
2|222
3|333
4|444
恢复前需要用ODU_0000052594.sql重建表,改文件需要手动修改表名和列名,把表名两边的""删除。sqlldr的控制文件同样需要修改
表名和列名,以及列类型,把表名两边的""删除。其实把这三个文件的数据恢复到数据库中已经不再涉及到odu,因此可以根据自己
的需要手动修改表结构。
<d>恢复数据
登录SQLPLUS,先根据.sql文件重建表,然后通过sqlldr调用.ctl来恢复数据,具体操作和前面一样。留心检查一下恢复过程以及结果
会发现,恢复出来的结果有8行,而我们原来测试的表中只有4行数据。这是因为前面为了恢复delete的数据,我们将配置文件中的
unload_deleted  yes参数打开了,所以将第一次操作中被delete的数据都恢复了出来,下个实验我们将验证一下这个参数关闭后的
效果。

(5)恢复truncate的表

<a>模拟测试数据,因为要测试unload_deleted参数,所以我们先删除5行数据,然后在truncate表,这样恢复的结果应该是3行数据
。将表offline后做一个checkpoint,更新数据字典。这里可以发现drop purge和truncate的区别,前者删除数据字典中的数据,后
者没有删除。
SQL> delete from (select * from test1) where rownum <=5;
5 rows deleted.
SQL> commit;
SQL> truncate table test1;
SQL> conn / as sysdba
SQL> alter tablespace users offline;
SQL> alter system checkpoint;
<b> 恢复依旧是根据object id来做,老熊的BLOG里介绍了另外几种方式查询object id。dump数据块头的内容来查看object id的方
式这里就不记录了,有兴趣的可去老熊的BLOG查看《使用ODU恢复Truncate表》。
ODU> unload dict
如果表数据任在数据字典中,导出数据结构后可根据desc命令查看表的结构和所在数据文件。新建后的object id已变更Object
ID:52596。
ODU> desc mwz.test1
Object ID:52596
Storage(Obj#=52596 DataObj#=52597 TS#=4 File#=4 Block#=411 Cluster=0)
NO. SEG INT Column Name                    Null?     Type                          
--- --- --- ------------------------------ --------- ------------------------------
  1   1   1 c                                        NUMBER(38)                    
  2   2   2 d                                        VARCHAR2(20)                 
扫描一下4号数据文件,然后恢复表 需要指定object id,如果不指定则无法扫描到数据。关闭unload_deleted参数后,只恢复出3条
数据,delete的数据不会被恢复出来。
ODU>scan extent tablespace 4
ODU> unload table mwz.test1
Unloading table: TEST1,object ID: 52596
Unloading segment,storage(Obj#=52596 DataObj#=52597 TS#=4 File#=4 Block#=411 Cluster=0)
0 rows unloaded
ODU> unload table mwz.test1 object 52596
Unloading table: TEST1,object ID: 52596
Unloading segment,storage(Obj#=52596 DataObj#=52596 TS#=4 File#=4 Block#=411 Cluster=0)
3 rows unloaded
<c>恢复到数据库的过程和前面的实验方法相同。
 

(6)复杂类型的表恢复

<a>模拟实验数据
本实验数据取自dba_objects视图,并添加一个clob字段,clob字段为72个英文字母,test2表总共50399行数据。OBJECT_ID列做索引
,测试能否恢复。假设system表空间损坏,无法读取数据字典,必须直接扫描数据文件。users数据文件不离线,测试能否恢复。
odu配置文件中手动设置LOB_STORAGE、LOB_PATH参数,将clob导出到其他目录。
SQL> desc test2
Name           Type          Nullable Default Comments 
-------------- ------------- -------- ------- -------- 
OWNER          VARCHAR2(30)  Y                         
OBJECT_NAME    VARCHAR2(128) Y                         
SUBOBJECT_NAME VARCHAR2(30)  Y                         
OBJECT_ID      NUMBER        Y                         
DATA_OBJECT_ID NUMBER        Y                         
OBJECT_TYPE    VARCHAR2(19)  Y                         
CREATED        DATE          Y                         
LAST_DDL_TIME  DATE          Y                         
TIMESTAMP      VARCHAR2(19)  Y                         
STATUS         VARCHAR2(7)   Y                         
TEMPORARY      VARCHAR2(1)   Y                         
GENERATED      VARCHAR2(1)   Y                         
SECONDARY      VARCHAR2(1)   Y                         
CLB            CLOB          Y             

<b> 修改odu配置文件、控制文件
新建/opt/odu/lobdata目录
mkdir /opt/odu/lobdata
config.txt添加LOB_STORAGE参数
LOB_PATH /opt/odu/lobdata
LOB_STORAGE file
<c>开始恢复
ODU> scan extent tablespace 4
扫描表空间的所有对象,odu会把所有的表对象记录全部导出,生成txt文件。
ODU> unload object all sample
[oracle@dns1 data]$ ls
ODU_0000051146.txt  ODU_0000052389.txt  ODU_0000052399.txt  ODU_0000052408.txt  ODU_0000052440.txt 
ODU_0000052684.txt
ODU_0000051147.txt  ODU_0000052390.txt  ODU_0000052400.txt  ODU_0000052409.txt  ODU_0000052441.txt 
ODU_0000052685.txt
ODU_0000051148.txt  ODU_0000052392.txt  ODU_0000052401.txt  ODU_0000052410.txt  ODU_0000052442.txt 
ODU_0000052686.txt
ODU_0000051149.txt  ODU_0000052393.txt  ODU_0000052402.txt  ODU_0000052411.txt  ODU_0000052443.txt 
ODU_0000052687.txt
ODU_0000051150.txt  ODU_0000052394.txt  ODU_0000052403.txt  ODU_0000052412.txt  ODU_0000052444.txt 
ODU_0000052688.txt
ODU_0000051151.txt  ODU_0000052395.txt  ODU_0000052404.txt  ODU_0000052413.txt  ODU_0000052597.txt 
ODU_0000052689.txt
ODU_0000052385.txt  ODU_0000052396.txt  ODU_0000052405.txt  ODU_0000052414.txt  ODU_0000052681.txt 
ODU_0000052690.txt
ODU_0000052387.txt  ODU_0000052397.txt  ODU_0000052406.txt  ODU_0000052438.txt  ODU_0000052682.txt  sample.txt
ODU_0000052388.txt  ODU_0000052398.txt  ODU_0000052407.txt  ODU_0000052439.txt  ODU_0000052683.txt
从sample.txt中手动查找需要恢复的对象,需要根据原表信息自己判断。比如我知道test2表有14列,以下结果应该是我们的表,
Sample结果显示只有1001行,这个暂时不管。
Sample result:
  object id: 52681
  tablespace no: 4
  sampled 1001 rows
  column count: 14
  column    1  type: VARCHAR2
  column    2  type: VARCHAR2
  column    3  type: VARCHAR2
  column    4  type: NUMBER
  column    5  type: NUMBER
  column    6  type: VARCHAR2
  column    7  type: DATE
  column    8  type: DATE
  column    9  type: VARCHAR2
  column   10  type: VARCHAR2
  column   11  type: VARCHAR2
  column   12  type: VARCHAR2
  column   13  type: VARCHAR2
  column   14  type: NVARCHAR2
First 5 rows:
SYS|ICOL$||20|2|TABLE|2005-06-30 19:10:16|2005-06-30 19:28:30|2005-06-30:19:10:16|VALID|N|N|N|
SYS|I_USER1||44|44|INDEX|2005-06-30 19:10:16|2005-06-30 19:10:16|2005-06-30:19:10:16|VALID|N|N|N|
SYS|CON$||28|28|TABLE|2005-06-30 19:10:16|2005-06-30 19:40:11|2005-06-30:19:10:16|VALID|N|N|N|
SYS|I_OBJ#||3|3|INDEX|2005-06-30 19:10:16|2005-06-30 19:10:16|2005-06-30:19:10:16|VALID|N|N|N|
SYS|FILE$||17|17|TABLE|2005-06-30 19:10:16|2005-06-30 19:10:16|2005-06-30:19:10:16|VALID|N|N|N|
COMMAND: 
unload object 52681 tablespace 4 column VARCHAR2 VARCHAR2 VARCHAR2 NUMBER NUMBER VARCHAR2 DATE DATE VARCHAR2
VARCHAR2 VARCHAR2 VARCHAR2 VARCHAR2 NVARCHAR2
将UNLOAD命令中列类型修改成原表类型测试下能否导入:
unload object 52681 tablespace 4 column VARCHAR2 VARCHAR2 VARCHAR2 NUMBER NUMBER VARCHAR2 DATE DATE VARCHAR2
VARCHAR2 VARCHAR2 VARCHAR2 VARCHAR2 clob
运行报错,将clob改回NVARCHAR2 。
ODU> unload object 52681 tablespace 4 column VARCHAR2 VARCHAR2 VARCHAR2 NUMBER NUMBER VARCHAR2 DATE DATE VARCHAR2
VARCHAR2 VARCHAR2 VARCHAR2 VARCHAR2 NVARCHAR2
Unloading Object,object ID: 52681,  Cluster: 0
50399 rows unloaded
恢复成功50399 rows ,但是检查ODU_0000052681.txt和/opt/odu/lobdata目录发现clob列没有恢复。在老熊的网站发现以下描述“
目前不支持没有数据字典(和SYSTEM表空间)时的IOT表和LOB类型的列。”
继续实验,这次扫描system表空间的数据字典,看能否恢复clob列。首先要在控制文件control.txt中添加system表空间信息,然后
重新读取控制文件。可以用 open命令,或者重新启动odu自动读取。
ODU> open
 ts#   fn  rfn bsize   blocks bf offset filename
---- ---- ---- ----- -------- -- ------ --------------------------------------------
   0    1    1  8192    62720 N       0 /database/app/oracle/oradata/orcl/system01.dbf
   4    4    4  8192     3360 N       0 /database/app/oracle/oradata/orcl/users01.dbf
load control file 'control.txt' successful
ODU> unload dict 
发现open命令虽然显示读取控制文件成功,但是无法正确读取数据字典。于是退出重新启动odu,让其自行读取。
ODU> list table mwz
      OBJ#   OBJECT_NAME                   
----------   ------------------------------
ODU> list user
     USER#   USERNAME                      
----------   ------------------------------
ODU> exit
ODU> desc mwz.test2

Object ID:52681
Storage(Obj#=52681 DataObj#=52681 TS#=4 File#=4 Block#=443 Cluster=0)
NO. SEG INT Column Name                    Null?     Type                          
--- --- --- ------------------------------ --------- ------------------------------
  1   1   1 OWNER                                    VARCHAR2(30)                  
  2   2   2 OBJECT_NAME                              VARCHAR2(128)                 
  3   3   3 SUBOBJECT_NAME                           VARCHAR2(30)                  
  4   4   4 OBJECT_ID                                NUMBER                        
  5   5   5 DATA_OBJECT_ID                           NUMBER                        
  6   6   6 OBJECT_TYPE                              VARCHAR2(19)                  
  7   7   7 CREATED                                  DATE                          
  8   8   8 LAST_DDL_TIME                            DATE                          
  9   9   9 TIMESTAMP                                VARCHAR2(19)                  
 10  10  10 STATUS                                   VARCHAR2(7)                   
 11  11  11 TEMPORARY                                VARCHAR2(1)                   
 12  12  12 GENERATED                                VARCHAR2(1)                   
 13  13  13 SECONDARY                                VARCHAR2(1)                   
 14  14  14 CLB                                      CLOB             
恢复test2的数据
ODU> unload table mwz.test2
Unloading table: TEST2,object ID: 52681
Unloading segment,storage(Obj#=52681 DataObj#=52681 TS#=4 File#=4 Block#=443 Cluster=0)
50399 rows unloaded
[oracle@dns1 data]$ ls
MWZ_TEST2.ctl  MWZ_TEST2.sql  MWZ_TEST2.txt
[oracle@dns1 data]$ more MWZ_TEST2.sql
CREATE TABLE "MWZ"."TEST2"
(
    "OWNER" VARCHAR2(30) ,
    "OBJECT_NAME" VARCHAR2(128) ,
    "SUBOBJECT_NAME" VARCHAR2(30) ,
    "OBJECT_ID" NUMBER ,
    "DATA_OBJECT_ID" NUMBER ,
    "OBJECT_TYPE" VARCHAR2(19) ,
    "CREATED" DATE ,
    "LAST_DDL_TIME" DATE ,
    "TIMESTAMP" VARCHAR2(19) ,
    "STATUS" VARCHAR2(7) ,
    "TEMPORARY" VARCHAR2(1) ,
    "GENERATED" VARCHAR2(1) ,
    "SECONDARY" VARCHAR2(1) ,
    "CLB" CLOB 
);
[oracle@dns1 data]$ head 1  MWZ_TEST2.txt
head: cannot open `1' for reading: No such file or directory
==> MWZ_TEST2.txt <==
SYS|ICOL$||20|2|TABLE|2005-06-30 19:10:16|2005-06-30 19:28:30|2005-06-
30:19:10:16|VALID|N|N|N|/opt/odu/lobdata/lob52682_0014/lob52682_0000000001.dat
     从恢复的表结构中可以发现,clob类型已经认到,并且记录数据的txt文件中也将clob文件地址连接放入记录中,应该用sqlldr能直接读取。但是索引并没有恢复,其实仔细想下不难理解,对于oracle来说table 和 index都是对象,odu其实是根据object id来恢复的,恢复表的时候odu自动匹配object id不会去判断该表是否还有索引。
     最后的实验兵没有
     用sqlldr导入后,发现clob数据存在问题,字符串只有第一个字母被导入,检查txt文件和lobdata目录里的文件,都只导出了1个字母。LOB_STORAGE 参数file和infile都试过,之前的测试并没有offline数据文件,最后重复测试发现和这也没关系。offline数据文件的一个重要作用就是自动生成checkpoint,这样会更新数据字典,并且把data buffer里的脏块写到数据文件。这里可以手动做一个checkpoint,alter system checkpoint。发现不做checkpoint,有时导出的数据行数或表结构会不全,但是clob内容缺失和这个没关系。最后发现是clob_byte_order 参数的问题,由于没有仔细阅读老熊《odu配置文件》一文,对该参数没有留意,导致后期花费了很多时间解决clob导出乱码以及数据缺失的问题。如果表内有lob字段,一定要正确修改clob_byte_order参数。
 

总结:老熊的ODU非常好用,不管是delete,drop还是truncate,只要数据还保存在物理文件中,odu就能恢复。即使系统表损坏,并
且无法恢复导致数据库不能启动,也能通过odu直接扫描业务表的数据文件,将表结构和数据恢复出来,然后用sqlldr导入到备用库
或新建的库中。其实进一步研究会发现odu并不仅仅是恢复工具,在你的表没有被drop、truncate或delete的情况下,也能用odu将数
据直接从数据文件中读取出来,其实把odu当成一个数据抽取工具更合适。
疑惑:那ORACLE到底什么情况下会清除或者重写物理文件中的记录?oracle 什么情况下会收缩数据文件?记得盖国强的书里描述过
该问题,有空会整理一下相关知识。

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

1

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广