达梦DTS数据迁移工具生产篇(Oracle->DM8)
本文章使用的DTS工具为 2024年9月18日的版本,使用的目的端DM8数据库版本为2023年12月的版本,注意数据库版本和DTS版本之间跨度不要太大,以免出现各种兼容性的报错。若发现版本差距过大时,请联系达梦技术服务工程师处理。
1. 迁移前检查
- 目的端DM8的页大小,要与源端Oracle库一致,未知时建议用32K。
- 目的端DM8的字符集编码,要与源端一致,uft-8或utf-8mb4的统一用utf-8,gbk或其他类型gbk的统一用GB18030,初始化参数CHARSET决定。
- 目的端DM8的空格检索建议为开启,若不开启建议重新初始化实例开启,或者Oracle新建表,插入数据'AA'和'AA ',其中第二个AA末尾带有一个空格,然后查询where name='AA',若第二个带空格的AA不出现,则必须开启空格检索,初始化参数BLANK_PAD_MODE=1。
- 目的端DM8的dm.ini修改参数COMPATIBLE_MODE=2。
2. 准备工作
目的端DM8创建好对应的表空间、用户,与源端保持一致。
2.1 创建表空间
生产环境,每个用户需要创建2个表空间,一个用于存放数据,一个用于存放索引。表空间条件满足如下:
- 每个文件大小size设置为128;
- 自动扩充打开;
- 扩充尺寸不写,扩充上限配置为102400或204800(即100G/200G),具体根据磁盘空间确定,存放索引的表空间可以配置为51200;
- 生产环境要求存放数据的表空间最少配置4个表空间文件,若磁盘空间不足时,可将扩充上限配置为51200,甚至20480均可,不够用时再添加新文件;
- 生产环境要求索引表空间最少配置2个表空间文件,若磁盘空间不足时,可将扩充上限配置为20480,甚至10240,不够用时再添加新文件。
示例:
--数据表空间
create tablespace "TEST_DAT" datafile 'TEST_DAT01.DBF' size 128 autoextend on maxsize 102400 CACHE = NORMAL;
--索引表空间
create tablespace "TEST_IDX" datafile 'TEST_IDX01.DBF' size 128 autoextend on maxsize 51200 CACHE = NORMAL;
2.2 创建用户
生产环境创建用户,必须配置表空间、索引表空间。
示例:
--创建普通用户TEST
create user "TEST" identified by "TEST123456" password_policy 31
default tablespace "TEST_DAT" --对应上方的数据表空间
default index tablespace "TEST_IDX"; --对应上方的索引表空间
grant "PUBLIC","RESOURCE","SOI","VTI" to "TEST"; --这是基础授权,其中RESOURCE角色权限是创建常用对象、写数据的权限
grant CREATE SESSION to "TEST"; --必给,不然创建不了会话
--TEST是用户名,TEST123456是密码
--default tablespace "TEST_DAT" 是该用户默认使用的数据表空间
--default index tablespace "TEST_IDX" 是该用户默认使用的索引表空间
--password_policy 31是密码策略,不写时默认使用系统统一策略
/*
0: 无策略;
1: 禁止与用户名相同;
2: 口令长度不小于 9;
4:至少包含一个大写字母(A-Z);
8 :至少包含一个数字(0-9);
16:至少包含一个标点符号(英文输入法状态下,除―和空格外的所有符号);
若为其他数字,则表示配置值的和,如 3=1+2,表示同时启用第 1 项和第 2 项策略,31就是全部启用。当COMPATIBLE_MODE=1 时,PWD_POLICY 的实际值均为 0
*/
3. 开始迁移
3.1 新建工程







如上图,这里要注意,尽量使用Oracle的业务用户,即应用服务连接Oracle使用的用户,尽量不要使用Oracle的系统用户(如SYSTEM),因为迁移时,DTS会把Oracle的系统表、系统包等也视为需要迁移的对象,导致迁移出现报错,干扰你的判断。除非你对Oracle很熟悉,一眼就能看出这是系统表、系统包,直接取消它们的迁移,防止干扰,这样可以使用Oracle的系统用户。
如上图,如果没有“数据库版本”选项,则可能你使用的DTS版本较低,这不影响,直接正常连接即可。

如上图,这步骤是可选操作,一般情况下DTS自带的JDBC驱动包能连接大部分版本的Oracle,但有时也会无法连接,或连接上了但是迁移出现少数据、少字段等问题,所以DTS工具允许使用其他途径获取到的JDBC驱动包。驱动包获取途径见下方。
补充说明:DTS工具连Oracle其实是使用JDBC的方式连接,所以需要jdbc驱动包,连接串url也跟寻常的java应用服务相同,所以即使你的DTS工具为较低版本,实际也能连接各种Oracle库。
jdbc驱动包获取途径:
(1)在Oracle所在服务器搜索ojdbc*.jar寻找
(2)找业务开发让他们从java应用服务包里获取,一般在lib目录下


如上图,这里“自定义URL”选项,一般是比较特别的Oracle库会使用到,因为DTS自动生成的jdbc连接串URL,可能无法连接Oracle,此时就需要手工配置URL,就会勾选这个选项,常见比如Oracle 19c PDB。平时不勾选,连不上库时可以尝试勾选,并查看java应用服务连接Oracle的URL,看下有无差别。
以上,均没问题后,下一步

如上图,这里可以使用SYSDBA用户,但也可以使用2.2章节创建的用户。



3.2 迁移自定义类型
因为有些表,会使用自定义类型,所以最优先迁移

如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有自定义类型,直接跳过本章节。







以上就是自定义类型的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.3 迁移序列
同样的,表可能会使用序列,所以我们迁移完自定义类型后,开始迁移序列。


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有序列,直接跳过本章节。







以上就是序列的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.4迁移表(表结构)
迁移表,分三步,先结构,再数据,最后才是索引约束



如上图,若使用的DTS版本过旧,则可能有些功能不会显示出来,此时只需注意,少的功能就当没看见即可。若使用的DTS版本比本文章高,有更多新功能出现,则点击左下角?按钮召唤文档查看功能详解。


下方是补图:

如上图,这是补图,第一次迁移可忽略



以上就是表结构的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.5 迁移表(表数据)




如上图,主键冲突处理,这个也是第二次迁移时才勾选,默认覆盖即可



以上就是表数据的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,最常见的可能是java内存溢出,或者违反唯一约束等,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.6 迁移表(约束索引)






以上就是表的约束索引的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,最常见的是违反唯一性约束,这种都是有重复数据导致唯一键创建失败,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
至此,迁移表结束。
3.7 迁移视图


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有视图,直接跳过本章节。





以上就是视图的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.8 迁移物化视图

如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有视图,直接跳过本章节。
物化视图迁移步骤同“迁移视图”章节,这里不在赘述。
3.9 迁移存储过程/函数


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有存储过程或函数,直接跳过本章节。




以上就是存储过程与函数的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.10 迁移触发器


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有触发器,直接跳过本章节。





以上就是触发器的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.11 迁移包


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有包,直接跳过本章节。





以上就是包的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
3.12 迁移同义词


如上图,步骤2转换,可以略过,一般只在第二次重复迁移时才会用到,或者有特殊迁移需求时才会用到。
如上图,若这一步骤为空,什么都没有显示,表示该Oracle源库没有同义词,直接跳过本章节。




以上就是同义词的迁移,遇到报错时,可将报错的sql复制后,在manager管理工具执行,查看报错情况,一般是语法不兼容需要改写,可查看本文章末尾“常见报错”寻找对应报错处理,或联系达梦工程师查看。
4. 常见报错
更多报错处理方案见达梦在线服务平台:从 Oracle 迁移到 DM | 达梦技术文档
4.1 记录超长
这个是数据太长导致,数据库是以页为单位作为存储,初始化参数中的页大小决定一条数据的大小,当数据的大小超出时就会报错。
解决方案:
(1)可以启用超长记录
alter table 表名 enable using long row ;
打开后,一条记录的页的存储空间就不会受限制。但是要注意,若插入数据的列有索引,则可能会报错,反之,插入后再给这个列创建索引时也可能会报错。
(2)提高页大小,但初始化库后页大小不能修改,所以只能新初始化一个库,将页大小设置高一些再迁移数据,一般存储不紧张时,且数据较大时,建议用32k页大小,因此迁移前尽量保证页大小与源库相同。
4.2 非法的基类名XXX
这个报错是迁移的对象中,引用了源库自带的系统函数或存储过程,在DM中没有同名时导致。或者是该系统函数或存储过程,在源库中属于模式A,但在DM中属于模式B,通过修改DDL把A成B也可以。
解决方案:
可以查询DM8的手册,找到对应功能的存储过程或函数,将迁移对象的DDL改写,或创建同名的公共同义词。手册见数据库安装目录的doc目录下,或在达梦在线服务平台查找:函数 | 达梦技术文档
4.3 XXX附近存在错误/语法分析错误
这个报错是迁移对象的DDL中XXX处的SQL写法,与DM8不一致导致,需要将对象的DDL进行改写。常见的有使用了Oracle特有的语法但DM不支持,所以报错那部分写法存在错误。
第二种情况是SQL中有关键字,比如percent,这时需要将关键字用双引号括起并改为大写,或者将关键字添加到屏蔽参数里,如下:
(1)可以在dm_svc.conf中添加KEYWORDS参数,并使用服务名连接数据库。
(2)登录数据库执行sp_set_para_string_value(2,'EXCLUDE_RESERVED_WORDS','关键字大写'); ,若为集群,则集群中每个节点都要执行,需要重启数据库才能生效。
4.4 无效的过程/函数名
这个报错是迁移的对象引用了源库的系统函数或存储过程,且DM8正好有同名同功能的函数或存储过程,但是参数位置、数量可能不相同,导致的报错,需要将对象的DDL进行改写。 手册见数据库安装目录的doc目录下,或在达梦在线服务平台查找:函数 | 达梦技术文档
4.5 无效的对象XXX
这个报错是迁移的对象中,引用了其他对象,但是引用的对象没有迁移或编译不过导致,需要将引用的对象迁移,或者编译通过,然后再迁移该报错对象。
4.6 无法解析的成员访问表达式XXX
这个报错是迁移对象的DDL中XXX处的SQL写法,与DM8不一致导致,与4.3章节有点像,也是需要将对象的DDL进行改写,比如,将USERENV('LANG')改为SYS_CONTEXT('USERENV','LANG')。
4.7 无效的表或视图XXX
这个报错是迁移对象的DDL中调用了源库的系统表或系统视图,在DM中没有同名时导致,需要将对象的DDL进行改写。
4.8 错误的日期时间类型格式XXX
这个报错是时间类型数据格式不一致引起,比如:2021-09-22 18:35:14.788+08,要去掉“+08”时区,因为DM需要+号前有空格,去掉后也不影响,插入时DM会为数据自动生成+08时区。
可以在3.1章节处,配置时间日期类型格式

4.9 数据类型不匹配
这个报错非常好理解,就是插入的数据与DM中的字段类型不匹配,比如bit类型,在某些库中是false和true,在DM是0和1,根据业务情况修改即可。
4.10 数据大小已超过可支持范围
这个报错是数据已经超过了字段类型的最大精度,那只能修改成大字段,比如TEXT。
4.11 列[XXX]长度超出定义
这个是迁移的XX表中,XXX列的字段类型的精度不足,增加精度即可解决,一般是将现有精度,扩容2~3倍,比如varchar(200)就扩容至600,varchar(4000)就扩2倍至8000,长度越长,就适当扩2倍即可,越短的,就扩3倍。这个报错原因是可能源库用了GBK,而DM8这边用了UTF-8。
4.12 字符串截断
与4.11章节类似,一般是表的列,字段类型精度不够,扩展2~3倍即可解决,比如现在的varchar(10),可将其扩展至20或30,其他列也是相同操作,2000及以上的精度可暂时不做扩展,除非其他列都扩展后还是有报错,再考虑扩展该长度的列。该报错最常见的就是varchar或varchar2的精度引起。
4.13 违反XXX唯一性约束
这个是创建唯一约束时,有重复数据导致(唯一约束就是唯一索引,也可以叫唯一键,意思就是想让表中的某个列,数据唯一,没有重复)。
可以使用以下SQL排查:
--查看数据重复
select 列1,count(*) from "表名大写" group by 列1 having count(*) > 1;
--这里的列1,来源于报错“违反XXX唯一性约束”里的列,XXX是约束名称,找到这个约束并查看它是对哪个列配置的,即可得知列1是哪个列名。
多个列时,select后面写多个列,但最后别忘了加上一个count(*),group by处与select处相同,只是不含count(*)。源库、目的库都执行排查。
4.14 java heap space / gc overhead limit exceeded
这是DTS工具运行内存不足,报错的java内存溢出,修改dts.ini,添加或修改参数-Xmx=4096,不用设置太高,java本身上限不高,再高java也撑不住。dts.ini在D:\dmdbms\tool目录下。
-Xms1024m <======JVM初始分配的堆内存
-Xmx4096m <======JVM最大允许分配的堆内存
修改后重启DTS,若还是有报错,则可能Oracle的数据实在过长,比如一张中有大量的varchar(3000)或varchar(4000)这种长度的数据,那就容易报内存溢出的错误,可尝试降低“源一次读取行数”和“目的端一次提交行数”,并行设为1。
4.15 违反协议
这是使用的Oracle驱动不匹配引起的报错,更换与Oracle版本对应的ojdbc驱动解决。
5. 数据对比
这里是手工对比,DTS工具现已支持数据对比,只要会使用迁移功能,对比功能自然也会,但实际使用起来可能会有些许问题,不嫌麻烦可以尝试以下手工对比:
执行以下SQL,会打印出对比的SQL,将其全部复制出来后,再执行,即可得到源库与新库的数据情况,粘贴到EXCEL里进行对比即可。
Oracle的:
--Oracle
--表数据
select 'select count(*) from '||owner||'.'||table_name||' union all' from all_tables where owner='模式名大写' order by table_name asc;
--主键
select owner,constraint_name,status from all_constraints where owner='模式名大写' and constraint_type = 'P' order by 1,2,3 asc;--注意将复制出来的sql里,最后一条sql末尾的union all删掉,改为分号即可
--外键
select owner,constraint_name,status from all_constraints where owner='模式名大写' and constraint_type = 'R' order by 1,2,3 asc;
--索引
create table ORACLE_INDEX_COUNT AS
select owner,index_name,index_type,status from all_indexes where owner='模式名大写' and index_name not like 'SYS_%' AND index_name not like '%_PK' order by 1,2,3,4 asc;
--注释
select owner,table_name,column_name,comments from all_col_comments where schname = '模式名大写' order by 1,2,3 asc;
--同义词:
select owner,synonym_name from dba_synonyms where owner='模式名大写' order by 1,2 asc;
--序列
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='SEQUENCE' order by 1,2,3 asc;
--视图
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='VIEW' order by 1,2,3 asc;
--函数
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='FUNCTION' order by 1,2,3 asc;
--存储过程
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='PROCEDURE' order by 1,2,3 asc;
--触发器
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='TRIGGER' order by 1,2,3 asc;
--自定义类型
select owner,object_name,status from all_objects where owner='模式名大写' and object_type in ('TYPE','TYPE BODY','CLASS') order by 1,2,3 asc;
--包
select owner,object_name,status from all_objects where owner='模式名大写' and object_type in ('PACKAGE','PACKAGE BODY') order by 1,2,3 asc;
DM8的:
--表数据
select 'select count(*) from '||owner||'.'||table_name||' union all' from all_tables where owner='模式名大写' order by table_name asc;--注意将复制出来的sql里,最后一条sql末尾的union all删掉,改为分号即可
--主键
select owner,constraint_name,status from all_constraints where owner='模式名大写' and constraint_type = 'P' order by 1,2,3 asc;
--外键
select owner,constraint_name,status from all_constraints where owner='模式名大写' and constraint_type = 'R' order by 1,2,3 asc;
--索引
select owner,index_name,index_type,status from all_indexes where owner='模式名大写' and index_name not like 'INDEX%' order by 1,2,3,4 asc;
--注释
select schname,tvname,colname,comment$ from syscolumncomments where schname = '模式名大写' order by 1,2,3 asc;
--同义词:
select owner,synonym_name from dba_synonyms where owner='模式名大写' order by 1,2 asc;
--序列
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='SEQUENCE' order by 1,2,3 asc;
--视图
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='VIEW' order by 1,2,3 asc;
--函数
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='FUNCTION' order by 1,2,3 asc;
--存储过程
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='PROCEDURE' order by 1,2,3 asc;
--触发器
select owner,object_name,status from all_objects where owner='模式名大写' and object_type ='TRIGGER' order by 1,2,3 asc;
--自定义类型
select owner,object_name,status from all_objects where owner='模式名大写' and object_type in ('TYPE','TYPE BODY','CLASS') order by 1,2,3 asc;
--包
select owner,object_name,status from all_objects where owner='模式名大写' and object_type in ('PACKAGE','PACKAGE BODY') order by 1,2,3 asc;
当发现数据不一致时,或者数据有重复时,可以使用以下SQL排查:
--查看数据重复
select 列1,count(*) from "表名大写" group by 列1 having count(*) > 1;
社区地址:快速上手 | 达梦技术文档
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)