暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

dul 11的研究

原创 wangx 2024-11-29
356

dul 11的研究

* dul的名气比较大,做oracle恢复的人都知道这个工具,但是这个工具是国外的开发的,发布的版本一般人也是下载不到的,类似这类的工具有很多,国内常见的有odu、aul、prmdul等。

* 最早的时候我是用过9和10的版本,当时恢复的是单纯的堆表,没有大字段的数据,导出的时候有两种选择,第一是csv,第二是dmp格式,但是我发现一个问题是如果用户的表较多,就会产生多个dmp出来,那么再加上恢复数据就变得更加复杂,曾经我用它在windows环境下恢复过几千个表,当时写的是windows的批处理脚本。过了几年,现在大部分都是11g~19c的环境,再用这个版本就不太合适。

* 关于该工具的使用方法网上有很多,我这里不做太多的介绍,主要讲一下它的弊端吧,对中文的clob支持不太友好,导出的是二进制的unicode编码,但是导进去是乱码,目前我还没解决,有相关经验的可以帮我解解惑。

* 关于该工具的使用特别要注意的是不同的版本都有时间的限制,如果想用对应的版本就要修改软件发布的对应的时间,另外还要修改文件的创建时间。这块在windows上比较麻烦,linux上很好处理,下面文章我有介绍。

* 下面正式进入实验:

一、环境说明

1、1 环境

[oracle@his dul]$ ./dul11205

Data UnLoader: 11.2.0.5.0 - Internal Only - on Mon May 1 00:25:22 2017
with 64-bit io functions and the decompression option

Copyright (c) 1994 2017 Bernard van Duijnen All rights reserved.

Strictly Oracle Internal Use Only

Cannot start now
You need a more recent DUL version for this os    --这里可以看到必须使用最近的dul,怎么解决呢?观察上面的Copyright (c) 1994 2017 Bernard van Duijnen All rights reserved. 只需要把操作系统时间改为2017年的,然后数据文件也改到那个时间。

再次打开dul就可以了


二、测试过程

2.1 配置dul说明

* 用过dul类似的工具都知道,dul的配置分为2个文件,一个是init.dul文件,另外一个是数据库的路径结构信息的文件control.dul(可自定义,按照init.dul配置的修改)。

2.2 配置init.dul

vi init.dul
OSD_BIG_ENDIAN_FLAG=FALSE    --大端还是小端
osd_dba_file_bits=10
osd_c_struct_alignment=32
osd_file_leader_size=1
OSD_WORD_SIZE=32
dc_columns=2000000
dc_tables=100000
dc_objects=100000
dc_users=8000
dc_segments=1000000
db_block_size=8192            --数据块尺寸
control_file=/dul/control.dul    --控制文件的位置
export_mode=true    --导出成dmp
#export_mode=false    --导出成csv,即sqlldr加载的文件
compatible=10             --兼容性参数,是什么版本就改成什么
buffer=200000000
#FILE_SIZE_IN_MB=1000
file=zlhis

2.3 配置control.dul

set heading off verify off trimspool on tab off echo off feedback off
set trimout on
set space 1 pagesize 0 linesize 999
set numwidth 3
select ts# || ' '|| rfile# || ' '|| name || ' block_size '|| block_size from v$datafile;

vi control.dul

2.4 初始化数据库字典信息

初始化后,在/dul目录下生成的文件信息

[oracle@his dul]$ ll
total 15448
-rw-r--r-- 1 oracle oinstall 752 May 1 00:09 ATTRIBUTE.ctl    --属性
-rw-r--r-- 1 oracle oinstall 1192966 May 1 00:09 ATTRIBUTE.dat
-rw-r--r-- 1 oracle oinstall 332 May 1 00:09 BOOTSTRAP.ctl    --引导
-rw-r--r-- 1 oracle oinstall 18907 May 1 00:09 BOOTSTRAP.dat
-rw-r--r-- 1 oracle oinstall 950 May 1 00:09 COL.ctl            --列
-rw-r--r-- 1 oracle oinstall 6627420 May 1 00:09 COL.dat
-rw-r--r-- 1 oracle oinstall 754 May 1 00:09 COLLECTION.ctl
-rw-r--r-- 1 oracle oinstall 127466 May 1 00:09 COLLECTION.dat
-rw-r--r-- 1 oracle oinstall 608 May 1 00:09 COLTYPE.ctl
-rw-r--r-- 1 oracle oinstall 162407 May 1 00:09 COLTYPE.dat
-rw-r--r-- 1 oracle oinstall 392 May 1 00:09 ICOL.ctl
-rw-r--r-- 1 oracle oinstall 175558 May 1 00:09 ICOL.dat
-rw-r--r-- 1 oracle oinstall 810 May 1 00:09 IND.ctl            --索引的控制文件
-rw-r--r-- 1 oracle oinstall 288360 May 1 00:09 IND.dat    --索引的数据文件
-rw-r--r-- 1 oracle oinstall 334 May 1 00:09 INDCOMPART.ctl
-rw-r--r-- 1 oracle oinstall 0 May 1 00:09 INDCOMPART.dat
-rw-r--r-- 1 oracle oinstall 678 May 1 00:09 INDPART.ctl
-rw-r--r-- 1 oracle oinstall 5563 May 1 00:09 INDPART.dat
-rw-r--r-- 1 oracle oinstall 684 May 1 00:09 INDSUBPART.ctl
-rw-r--r-- 1 oracle oinstall 0 May 1 00:09 INDSUBPART.dat
-rw-r--r-- 1 oracle oinstall 880 May 1 00:09 LOB.ctl        --lob相关信息
-rw-r--r-- 1 oracle oinstall 66978 May 1 00:09 LOB.dat
-rw-r--r-- 1 oracle oinstall 336 May 1 00:09 LOBCOMPPART.ctl
-rw-r--r-- 1 oracle oinstall 0 May 1 00:09 LOBCOMPPART.dat
-rw-r--r-- 1 oracle oinstall 608 May 1 00:09 LOBFRAG.ctl
-rw-r--r-- 1 oracle oinstall 40 May 1 00:09 LOBFRAG.dat
-rw-r--r-- 1 oracle oinstall 600 May 1 00:09 OBJ.ctl        --对象
-rw-r--r-- 1 oracle oinstall 4720362 May 1 00:09 OBJ.dat
-rw-r--r-- 1 oracle oinstall 254 May 1 00:09 PROPS.ctl    --数据库字符集等信息
-rw-r--r-- 1 oracle oinstall 1108 May 1 00:09 PROPS.dat
-rw-r--r-- 1 oracle oinstall 880 May 1 00:09 TAB.ctl        --表
-rw-r--r-- 1 oracle oinstall 238130 May 1 00:09 TAB.dat
-rw-r--r-- 1 oracle oinstall 334 May 1 00:09 TABCOMPART.ctl    --表分区相关
-rw-r--r-- 1 oracle oinstall 19 May 1 00:09 TABCOMPART.dat
-rw-r--r-- 1 oracle oinstall 678 May 1 00:09 TABPART.ctl
-rw-r--r-- 1 oracle oinstall 4498 May 1 00:09 TABPART.dat
-rw-r--r-- 1 oracle oinstall 684 May 1 00:09 TABSUBPART.ctl
-rw-r--r-- 1 oracle oinstall 1431 May 1 00:09 TABSUBPART.dat
-rw-r--r-- 1 oracle oinstall 318 May 1 00:09 TS.ctl            --表空间
-rw-r--r-- 1 oracle oinstall 729 May 1 00:09 TS.dat
-rw-r--r-- 1 oracle oinstall 392 May 1 00:09 TYPE.ctl        --type
-rw-r--r-- 1 oracle oinstall 233062 May 1 00:09 TYPE.dat
-rw-r--r-- 1 oracle oinstall 532 May 1 00:09 UNDO.ctl    --undo段
-rw-r--r-- 1 oracle oinstall 9721 May 1 00:09 UNDO.dat    
-rw-r--r-- 1 oracle oinstall 252 May 1 00:09 USER.ctl        --用户表
-rw-r--r-- 1 oracle oinstall 1778 May 1 00:09 USER.dat
-rwxrwxr-x 1 oracle oinstall 1904 Apr 1 2019 control.dul
-rw-r--r-- 1 oracle oinstall 6429 May 1 00:09 dict.ddl    --数据字典
-rw-r--r-- 1 oracle oinstall 20163 May 1 00:09 dul.log    --dul允许过程中的日志
-rwxrwxr-x 1 oracle oinstall 851656 Apr 1 2019 dul11205
-rwxrwxr-x 1 oracle oinstall 901896 Apr 1 2019 dul12.2
-rwxrwxr-x 1 oracle oinstall 383 May 1 00:03 init.dul


----dul允许过程中的日志这个文件是很重要的,它记录了dul启动后参数的配置情况和对应的版本里面的参数,如果不清楚对应版本的参数,从中可以找到。

----USERS.dat可以了解到改库的schema信息,可以为unload user做参考。

2.5 按表导出测试

--从上面可以看到,dul在linux下对中文的表单独导出支持不太友好,不知道是不是字符集环境设置得不对,我改了NLS_LANG\LANG都不行。

--导出英文表是可以得,导出完成后会在库下按照表名生成对应的dmp文件。

2.6 按库导出测试

DUL> unload user zlhis;

--上面可以看到表很多都是中文的,但是导出后去/dul目录,没有一张中文的表;

--为了解决这个中文的问题,我调整了参数:

--删除/dul目录下的.dmp文件,再次unload user zlhis;

--以上数据导出后,在导入的时候怎么弄,肯定不能单个文件去导入吧,所以我又写了脚本...


三、导入结果

3.1 准备相同版本的数据库,新建表空间、新建用户。

这一步简单,大家都会,跳过。

3.2 脚本

##方法1##
function read_dir(){
read -t 30 -p "输入路径: " d
read -t 30 -p "输入用户: " u
read -t 30 -p "输入用户密码: " p
rm /tmp/imp.sh &>/dev/null

for file in `ls $d/*.dmp`
do
#echo 正在执行---------file=$file 的$u导入------------------
echo imp $u/$p file=$file log=$file"."log full=y feedback=10000 buffer=10240000 commit=y ignore=y >>/tmp/imp.sh

done
}

daoru() {

i=0;
cat /tmp/imp.sh|while read line
do
if [ "$line" != "" ] && [ $i -lt 10 ];then
$line &
let i++;
processnum=`ps -ef|grep imp|grep -v grep|wc -l`
if [ $processnum -eq 10 ];then
wait
fi
elif [ "$line" != "" ] && [ $i -lt 20 ];then
$line &
let i++;
processnum=`ps -ef|grep imp|grep -v grep|wc -l`
if [ $processnum -eq 10 ];then
wait
fi
else
$line &
processnum=`ps -ef|grep imp|grep -v grep|wc -l`
if [ $processnum -eq 10 ];then
wait
fi
fi
done
wait
}

read_dir
daoru


##方法2##
#!/bin/bash
start_time=$(date +"%Y-%m-%d %H:%M:%S")
echo "Script started at $start_time"

USER="zlhis"
PASSWORD="his"

DUMP_DIR="/dul/dump1"
LOG_DIR="/dul/dump1"
FAILED_TASKS="$LOG_DIR/failed_tasks.txt"

MAX_CONCURRENT=100
#要小于数据库允许的并发,否则要提前修改 alter system set processes=1000 scope=spfile;

mkdir -p "$LOG_DIR" > "$FAILED_TASKS"
pids=() # 用于存储后台任务的 PID 列表

for dumpfile in "$DUMP_DIR"/*.dmp; do
dumpname=$(basename "$dumpfile" .dmp)
logfile="$LOG_DIR/$dumpname.log"

echo "开始导入: $dumpfile -> $logfile"

# 启动任务并将 PID 存储到数组中
(
imp userid=$USER/$PASSWORD file="$dumpfile" log="$logfile" full=y feedback=10000 buffer=10240000 commit=y ignore=y &>/dev/null
if [ $? -ne 0 ]; then
echo "$dumpfile" >> "$FAILED_TASKS"
fi
) &

pids+=($!) # 将后台任务 PID 添加到数组

# 检查并发数
while [ "${# pids[ @ ]}" -ge "$MAX_CONCURRENT" ]; do
for i in "${! pids[ @ ]}"; do
if ! kill "${ pids[i  ]}" 2>/dev/null; then
unset pids[i  ] # 移除已完成的任务
fi
done
pids=("${pids[ @ ]}") # 重建数组(移除空值)
sleep 1 # 等待片刻后再检查
done
done

# 等待所有剩余任务完成
for pid in "${ pids[ @ ]}"; do
wait "$pid"
done

if [ -s "$FAILED_TASKS" ]; then
echo "以下任务导入失败,请检查日志:"
cat "$FAILED_TASKS"
else
echo "所有任务成功完成!"
fi

end_time=$(date +"%Y-%m-%d %H:%M:%S")
echo "Script ended at $end_time"



ps -ef|grep dmp|wc -l

[oracle@his dump]$ ll *.dmp |wc -l
1045
[oracle@his dump]$ ll *.log|wc -l
1045

检查日志:
find ./ -name "*.log" |xargs grep -A 2 'importing table'|more

3.23 脚本导入

--导入过程中另外的窗口也可以打开观察进程和日志情况

--表已经进来。

如果有报错,可以看对对应的日志;

或者看dmp导入过程中的日志;

find ./ -name "*.log" |xargs grep -A 2 'importing table'|more

四、clob测试导出导入

1、创建带有CLOB字段的表:
sqlplus zlhis/his
CREATE TABLE clob_test (
id NUMBER,
clob_column CLOB
);

2、插入数据
INSERT INTO clob_test (id, clob_column) VALUES (1, TO_CLOB('这是一个CLOB字段的文本数据,啊发吉萨的房间里撒地方阿斯蒂芬'));
alter system flush buffer_cache;

3、查询数据
SELECT id, clob_column FROM zlhis.clob_test;


4、编写vi init.dul
OSD_BIG_ENDIAN_FLAG=FALSE
osd_dba_file_bits=10
osd_c_struct_alignment=32
osd_file_leader_size=1
OSD_WORD_SIZE=32
dc_columns=20000000
dc_tables=10000000
dc_objects=10000000
dc_users=8000
dc_segments=10000000
db_block_size=8192
control_file=/dul/control.dul
export_mode=true
#export_mode=false
compatible=11
buffer=2000000000
#FILE_SIZE_IN_MB=1000
file=zlhis
#LDR_OUTPUT_IN_UTF8=TRUE

5、dmp导出测试
show datafiles;
bootstrap;
scan database;

DUL> desc zlhis.clob_test;
Table ZLHIS.CLOB_TEST
obj#= 97187, dataobj#= 97191, ts#= 4, file#= 4, block#=301946
tab#= 0, segcols= 2, clucols= 0
Column information:
icol# 01 segcol# 01 ID len 22 type 2 NUMBER(0)
icol# 02 segcol# 02 CLOB_COLUMN len 4000 type 112 CLOB cs 852(ZHS16GBK)
LOB Segment: dataobj#= 97188, ts#= 4, file#= 4, block#=318850 chunk=1
LOB Index: dataobj#= 97189, ts#= 4, file#= 4, block#=318858

unload table zlhis.clob_test;
exit;

6、dmp导入测试
sqlplus zlhis/his
truncate table clob_test;
imp zlhis/his file=/dul/ZLHIS_CLOB_TEST.dmp log=/dul/ZLHIS_CLOB_TEST.log full=y feedback=10000 buffer=10240000 commit=y ignore=y

SELECT id, clob_column FROM clob_test;

[oracle@his dul]$ env|grep -i lang
NLS_LANG=american_america.ZHS16GBK
LANG=zh_CN.UTF-8

zh_CN
zh_CN.gb18030
zh_CN.gb2312
zh_CN.gbk
zh_CN.utf8

export LANG=zh_CN.gbk

7、sqlldr导出测试
修改init.dul

export_mode=false

sqlldr zlhis/his control=ZLHIS_CLOB_TEST.ctl

再次导入,还是乱码。网上搜索了下,看了两篇文章,还是没能解决这个问题

--https://tool.ip138.com/ascii/
--http://www.killdb.com/2014/09/14/%e5%a6%82%e4%bd%95%e8%a7%a3%e5%86%b3oracle-dul%e6%81%a2%e5%a4%8dclob%e6%97%b6%e4%b8%ad%e6%96%87%e4%b9%b1%e7%a0%81%e9%97%ae%e9%a2%98%ef%bc%9f/

[oracle@his dul]$ iconv -l|grep UCS

10646-1:1993/UCS4/
CSUCS4//
ISO-10646-UCS-2//
ISO-10646/UCS2/
ISO-10646/UCS4/
UCS-2//
UCS-2BE//
UCS-2LE//
UCS-4//
UCS-4BE//
UCS-4LE//
UCS2//
UCS4//
[oracle@his dul]$ iconv -l|grep GB
CN-GB//
CSGB2312//
CSISO58GB1988//
EBCDIC-CP-GB//
GB//
GB2312//
GB13000//
GB18030//
GBK//
GB_1988-80//
GB_198880//
ISO646-GB//

iconv -f UCS-4LE -t gb2312 ZLHIS_CLOB_TEST.dat > 1

cat 1

看了上面链接的文章,分析了数据,是unicode编码,用的"分割每列,空格一列后又是下一个字段,最后一个字段后是回车。通过iconv -f UCS-4LE -t gb2312 ZLHIS_CLOB_TEST.dat > 1还是不行。

五、总结

1、单表导出,测试中文不支持,要改为使用用户;unload 全库会遇到DUL: FATAL Error: UTF16 can only be unloaded if LDR_OUTPUT_IN_UTF8=TRUE

2、lob字段对中文支持不友好,可能是外国佬写的原因吧。

3、init.dul里面的最重要的几个参数要清楚,特别是不同版本的数据库这里要修改,不然bootstrap生成的内容不准确,数据就无法导出。

4、dul类似的工具是最后一步,通过上面的操作也能看到这仅仅是把数据导出来,然后恢复,其实还有约束、索引、触发器、函数等等工作需要做,这也就要求必须要有应用厂商的人配合恢复,或者要有一个对应版本的测试库环境。

写到最后,提醒各位做好备份,技术再高,也怕挨刀。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论