1、介绍
这篇文档描述如何使用DUL,而不是完整的DUL功能描述。
DUL是用来替代其他方法无法实现的数据校验。也就是无法用export和SQL*Loader。数据库可能被损坏但数据库必须100%是正确的。在导出时会检查确认所有的数据库都是正确的并属于正确的段。如果DUL发现了错误的块,错误信息会被输出到文件里,但是并不会中断导出下一行或下一个块。
2、使用DUL
首先要检查你要导出的对象是否有相应的信息在数据库里。
会去从USER$, OBJ$, TAB$ 和 COL$中检索信息。
DUL会从系统表空间里获取信息,系统表空间数据文件必须包含控制文件,如果系统表空间文件不存在,那么看第六步。
2.1创建合适的“init.dul”文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
REM平台指定参数(NT)
REM能获取的最常见平台的参数列表:。
osd_dba_file_bits=10
osd_c_struct_alignment=32
osd_file_leader_size=1
osd_word_size=32
REM dul字典缓冲区大小如果其中一个值过低,启动将会失败。
dc_columns=2000000
dc_tables=10000
dc_objects=1000000
dc_users=400
dc_segments=100000
控制文件的位置和文件名,默认值在control.dul里
REM 在当前的路径control_file=D:\Dul\control_orcl.dul
数据库块大小,可以在init.ora中的文件中找到,或在服务器管理器中执行“show parameter %db_block_size%” 被检索到,将该参数更改为损坏数据块的块大小。
db_block_size=4096
当数据需要导出/导入格式,它可以/必须被指定。REM必须制定导出/导入的文件格式。REM必须创建一个可以被入工具使用的文件,虽然生成的文件与由EXP工具生成的表模式导出完全不同。它是一个有创建表结构语句和表数据的表转储文件。grants,存储子句,触发器不包括在这个转储文件中!
export_mode=true
(false表示是sqlloader,true表示imp)
REM兼容参数可以设置为6,7或者8
compatible=8
该参数是可选的并能在REM不支持的长文件名(e.g. 8.3 DOS)的平台,或当文件格式DUL使用 “owner_name.table_name.ext”不可接受时被指定。在这里,转储文件会类似dump001.ext,dump002.ext,等。
file = dump
2.2创建”control.dul”文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在数据库mount的状态下,你可以执行下面的查询语句知道数据库的逻辑表空间和物理数据文件结构
Oracle 6, 7
———–
> connect internal
> spool control.DUL
> select * from v$dbfile;
> spool off
Oracle 8
——–
> connect internal
> spool control.DUL
> select ts#, rfile#, name from v$datafile;
> spool off
Edit the spool file and change, if needed, the datafile location and stripe out unnecessary information like table headers, feedback line, etc…
A sample control file looks something like this :
如果需要的话,编辑spool文件,数据文件的位置和stripe out不必要的信息,如表头,反馈行,等…
控制文件示例像这样:
REM Oracle7 control file
1 D:\DUL\DATAFILE\SYS1ORCL.DBF
3 D:\DUL\DATAFILE\DAT1ORCL.DBF
7 D:\DUL\DATAFILE\USR1ORCL.DBF
REM Oracle8 control file
0 |
1 |
D:\DUL\DATAFILE\SYS1ORCL.DBF |
1 |
2 |
D:\DUL\DATAFILE\USR1ORCL.DBF |
1 |
3 |
D:\DUL\DATAFILE\USR2ORCL.DBF |
2 |
4 |
D:\DUL\DATAFILE\DAT1ORCL.DBF |
注:每个条目可以包含一个数据文件的一部分,当你需要拆分对于DUL太大的数据文件时,这就有用了,这样每个部分就小于比方说2GB了。 例如 :REM Oracle8 其中一个数据文件被分割成多部分,每部分小于1G
0 1 D:\DUL\DATAFILE\SYS1ORCL.DBF
1 2 D:\DUL\DATAFILE\USR1ORCL.DBF startblock 1 endblock 1000000
1 2 D:\DUL\DATAFILE\USR1ORCL.DBF startblock 1000001 endblock 2000000
1 2 D:\DUL\DATAFILE\USR1ORCL.DBF startblock 2000001 endblock 2550000
2.3导出数据对象信息
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以适当DDL(DUL描述语言)脚本启动BUL工具。由于数据库版本不同,有3个可用脚本来导出USER$,$ OBJ,TAB$和COL$表。
Oracle6 :> dul8.exe dictv6.ddl Oracle7 :> dul8.exe dictv7.ddl Oracle8 :> dul8.exe dictv8.ddl
Data UnLoader: Release 8.0.5.3.0 – Internal Use Only – on Tue Jun 22 22:19: Copyright (c) 1994/1999 Bernard van Duijnen All rights reserved.
Parameter altered Session altered. Parameter altered Session altered. Parameter altered Session altered. Parameter altered Session altered.
. unloading table OBJ$ 2271 rows unloaded
. unloading table TAB$ 245 rows unloaded
. unloading table COL$ 10489 rows unloaded
. unloading table USER$ 22 rows unloaded
. unloading |
table |
TABPART$ | 0 | rows |
unloaded |
. unloading |
table |
IND$ | 274 | rows |
unloaded |
. unloading |
table |
ICOL$ | 514 | rows |
unloaded |
. unloading |
table |
LOB$ | 13 | rows |
unloaded |
这将 USER$, OBJ$, TAB$ and COl$ 数据字典表的数据导出到 SQL*Loader 文件,这不能被处理到导入格式的转储文件中。
参数 export_mode = false 被硬编码到ddl脚本且不能更改为值“true”,因为这会导致DUL产生错误而失败:
. unloading table OBJ$
DUL: Error: Column “DATAOBJ#” actual size(2) greater than length in column definition(1)
………….etc……………
2.4调用DUL
~~~~~~~~~~~~~~
在交互模式下启动DUL,你也可以准备一个包含所有ddl命令以导出数据库必要数据的脚本。我会在本文档中描述最常用的命令,但不是完整的可指定参数列表。
DUL> unload database;
=>这将导出整个数据库(包括SYS的表)
DUL> unload user
=> 这将导出所有特定用户所拥有的表。
DUL> unload table
=> 这将导出用户所指定的表
DUL> describe
将列出表的列信息。
DUL> scan database;
=> 扫描所有数据文件的所有块。
将产生两个文件:
1:seg.dat找到的段头的信息(索引/集群/表)(对象ID,文件号和块号)。
2:ext.dat连续的表/集群的数据块的信息。(对象ID(V7),文件和段头的块号(V6),文件号和第一个块的块号,块的数量,表数量)
DUL> scan tables;
=> 也会生成seg.dat 和ext.dat 两个文件.
扫描所有段上的所有的表
2.5重建数据库
~~~~~~~~~~~~~~~~~~~~~~~~
创建新的数据库,并使用导入或SQL * Loader来恢复被DUL检索到的数据。需要注意的是,当你只导出表结构数据时,索引,grants,PL / SQL和触发器将不再在新的数据库中存在。为了获得与之前数据库的完全相同的副本,你需要重新运行表,索引,PL / SQL等的创建脚本。
如果你没有这些脚本,那么你将需要执行在文档第3部分描述的步骤。
3. 如何重建存储在数据字典的数据定义
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
要通过DUL重建PL / SQL(程序包,过程,函数或触发器),grants,索引,约束或存储子句(旧的表结构)是可以的,但就是有点棘手。您需要使用DUL导出相关的数据字典表,然后加载这些表到一个新的数据库,一定要使用与SYS或system不同的用户。加载损坏数据库的数据字典表到新的数据库字典可能也会破坏新的数据库。
示例从损坏的数据库检索pl/sql 包/存储过程/函数p的详情:
1)按照在“使用DUL”一节中的步骤解释并导出数据字典表“source$”
2)创建一个新的用户登录到一个健康新数据库,并指定所需的默认和临时表空间。
3)将连接,资源, imp_full_database授权给新用户。
4)导入/加载表“source$”到新创建的模式:
例如:imp80 userid=newuser/passw file=d:\dul\scott_emp.dmp
log=d:\dul\impemp.txt full=y
5)现在你可以从newuser.source$表查询以在损坏的数据库中重建pl/sql packages / procedures /functions。在WebIv可以找到产生这样的PL / SQL创建脚本。
相同的步骤可以用于重建索引,约束,和存储参数,或者为相应的用户重新授权。请注意,你总是需要使用某种类型的脚本,可以重建对象并包括损坏的数据库版本的所有功能。例如:当损坏的数据库是7.3.4版本,你有几个位图索引,如果你会使用支持7.3.2版本或之前的脚本,那么你将无法成功重建位图索引!
4、当段头块损坏时如何导出数据
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
当DUL不能以正常方式检索数据块信息,它可以扫描数据库来创建其自己的段/区信息。要从数据文件导出数据,扫描数据库的过程是必要的。
(为了说明这个例子,我根据段头块复制一个空块)
1)创建init.dul和control.dul
2)导出表,会因为断头块有损坏而失败
DUL> unload table scott.emp;
. unloading table EMP
DUL: Warning: Block is never used, block type is zero DUL: Error: While checking tablespace 6 file 10 block 2
DUL: Error: While processing block ts#=6, file#=10, block#=2 DUL: Error: Could not read/parse segment header
0 rows unloaded
3)运行数据库扫描
DUL> scan database;
tablespace 0, data file 1: 10239 blocks scanned
tablespace 6, data file 10: 2559 blocks scanned
4)向DUL说明应该使用自己生成的段区信息,而不是端头块的信息
DUL> alter session set use_scanned_extent_map = true; Parameter altered
Session altered.
DUL> unload table scott.emp;
. unloading table EMP 14 rows unloaded
5、当数据文件头损坏时如何导出数据
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在你打开数据库时,总是会报数据文件头块损坏。这和段头块的损坏(见第4点)不一样,其中的数据库可以成功打开,且当你进行表查询时,才会报损坏错误信息。DUL从这种情况中恢复没有问题,尽管有其他恢复这种情况的方法,如为数据文件头块打补丁。
你将收到如下错误:
ORACLE instance started.
Total System Global Area 11739136 bytes Fixed Size 49152 bytes
Variable Size 7421952 bytes
Database Buffers 4194304 bytes
Redo Buffers 73728 bytes
Database mounted.
ORA-01122: database file 10 failed verification check
ORA-01110: data file 10: ‘D:\DATA\TRGT\DATAFILES\JUR1TRGT.DBF’
ORA-01251: Unknown File Header Version read for file number 10
6、如何在没有system表空间的情况下导出数据
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
如果系统表空间不可用,仍可继续导出,但对象信息无法从数据字典表USER $,OBJ $,$ TAB和COL $检索。所以所有者名称,表名和列名不会被加载到DUL字典。识别表会是一项艰巨的任务,且这里需要对RDBMS内部有很好的了解。
首先,你需要对你的应用和它的表有很好的了解。列类型可以有DUL猜测,但表和列名都将丢失。
任何同一个数据库旧的系统表空间(可能是几周前的)也可以有很大的帮助!
1)创建 “init.dul”文件和“control.dul”文件。在这种情况下,控制文件将包含所有你想要恢复的数据文件,但不需要系统表空间的信息。
2)然后调用DUL并输入以下命令:
DUL> scan database;
data file 6 1280 blocks scanned
这将创建区段和段信息。也许DUL命令解释程序也将被终止。
3)重新调用DUL命令解释器并执行以下操作:
Data UnLoader: Release 8.0.5.3.0 – Internal Use Only – on Tue Aug 03 13:33:
Copyright (c) 1994/1999 Oracle Corporation, The Netherlands. All rights res Loaded 4 segments
Loaded 2 extents Extent map sorted
DUL> alter session set use_scanned_extent_map = true;
DUL> scan tables; (or scan extents;)
Scanning tables with segment header Oid 1078 fno 6 bno 2 table number 0
UNLOAD TABLE T_O1078 ( C1 NUMBER, C2 UNKNOWN, C3 UNKNOWN ) STORAGE ( TABNO 0 EXTENTS( FILE 6 BLOCK 2));
Colno Seen MaxIntSz Null% C75% C100 Num% NiNu% Dat% Rid%
1 |
4 |
2 | 0% | 0% | 0% | 100% |
100% | 0% | 0% |
2 |
4 |
10 | 0% | 100% | 100% | 100% |
0% | 0% | 0% |
3 |
4 |
8 | 0% | 100% | 100% | 100% |
0% | 0% | 50% |
“10” “ACCOUNTING” “NEW YORK” “20” “RESEARCH” “DALLAS”
“30” “SALES” “CHICAGO”
“40” “OPERATIONS” “BOSTON”
Oid 1080 fno 6 bno 12 table number 0
UNLOAD TABLE T_O1080 ( C1 NUMBER, C2 UNKNOWN, C3 UNKNOWN, C4 NUMBER, C5 DATE, C6 NUMBER, C7 NUMBER, C8 NUMBER )
STORAGE ( TABNO 0 EXTENTS( FILE 6 BLOCK 12));
Colno | Seen | MaxIntSz | Null% | C75% | C100 | Num% | NiNu% |
Dat% |
Rid% |
1 | 14 | 3 | 0% | 0% | 0% | 100% | 100% |
0% |
0% |
2 | 14 | 6 | 0% | 100% | 100% | 100% | 0% |
0% |
21% |
3 | 14 | 9 | 0% | 100% | 100% | 100% | 0% |
0% |
0% |
4 | 14 | 3 | 7% | 0% | 0% | 100% | 100% |
0% |
0% |
5 | 14 | 7 | 0% | 0% | 0% | 0% | 0% |
100% |
0% |
6 | 14 | 3 | 0% | 0% | 0% | 100% | 100% |
0% |
0% |
7 | 14 | 2 | 71% | 0% | 0% | 100% | 100% |
0% |
0% |
8 | 14 | 2 | 0% | 0% | 0% | 100% | 100% |
0% |
0% |
“7369” “SMITH” “CLERK” “7902” “17-DEC-1980 AD 00:00:00” “800” “” “20”
“7499” “ALLEN” “SALESMAN” “7698” “20-FEB-1981 AD 00:00:00” “1600” “300” “30”
“7521” “WARD” “SALESMAN” “7698” “22-FEB-1981 AD 00:00:00” “1250” “500” “30”
“7566” “JONES” “MANAGER” “7839” “02-APR-1981 AD 00:00:00” “2975” “” “20”
“7654” “MARTIN” “SALESMAN” “7698” “28-SEP-1981 AD 00:00:00” “1250” “1400” “30”
Note : it might be best that you redirect the output to a logfile since commands like the “scan tables” can produce a lot of output.
On Windows NT you can do the following command :
C:\> dul8 > c:\temp\scan_tables.txt scan tables;
exit;
4)从步骤3的输出中找到丢失的表;如果你仔细看上面的输出会发现,unload语法已经给出,但表的名称将是格式T_0 ,列名称将是格式的C ;数据类型不会精确匹配之前的数据类型。
特别查找像“Oid 1078 fno 6 bno 2 table number 0”的字符串,其中:
oid = object id, will be used to unload the object 对象id,会被用于导出对象
fno = (data)file number (数据)文件号
bno = block number 块号
5)使用“unload table”命令导出找出的表:
DUL> unload table dept (deptno number(2), dname varchar2(14),
loc varchar2(13)) storage (OBJNO 1078)
Unloading extent(s) of table DEPT 4 rows.