在数据库替换项目里摸爬滚打这几年被问到最多的问题就是“Oracle到底怎么迁到达梦”。问这话的人通常刚接触达梦以为跟Oracle之间的expdp/impdp一样导入导出就完事了。直到他们发现上百个存储过程、一堆序列和触发器、几个分区表全要手工处理时才意识到事情没那么简单。我之前听赵渝强老师讲达梦数据库的数据迁移工具DTS他用了句很形象的话概括“从源库读结构、读数据再翻译成达梦能认的东西最后写进达梦。”这句话我一直记到现在。这篇文章就按这个思路把DTS从连接到校验的完整过程拆开讲一遍重点是我在实际项目中踩过的坑和调优经验给正在做迁移的DBA、后端开发和交付工程师做个参考。1. 为什么迁移到达梦先要弄懂DTS的定位1.1 换数据库最大的麻烦不在数据在对象很多人一开始觉得迁移嘛把数据导过去就行。真做起来才发现数据反而是最省心的一环麻烦全在数据库对象上。举个例子。一个典型的Oracle业务系统里通常有几百张表但还有几十个视图、几十个序列、上百个存储过程和函数、一堆触发器、同义词、物化视图、分区方案。这些对象不是孤立的它们互相引用存储过程调用视图触发器调用序列外键约束连着主键包里面套着函数和过程。如果只把表和数据搬过去应用程序一启动就会发现少这个缺那个连最简单的登录都跑不通。传统做法是手工写DDL脚本然后通过达梦的disql或者图形化管理工具执行。对于几个对象的小库这么搞没问题但几百张表加几百个对象人肉维护脚本的出错率就上来了。尤其是对象之间有依赖关系时执行顺序错了后边的对象全建不起来。1.2 DTS能管的事情正好覆盖这些麻烦DTS是达梦自带的图形化数据迁移工具全称就是Data Transformation Service。它跟达梦的其他工具定位不同disql是命令行交互工具适合执行SQLdmfldr是数据快速装载工具适合从文本文件往表里灌数据DTS则是专门用来把外部数据库“搬”进达梦的搬的范围包括结构和数据。DTS支持几种常见源端Oracle、SQL Server、MySQL、PostgreSQL、DB2、Informix也包括达梦自己。也就是说达梦到达梦的导库或者Oracle、MySQL往达梦迁都可以用它。它内部做了什么可以用一个流水线来理解连接源库把元数据读出来比如表结构、字段类型、约束、索引、触发器定义把源库的元数据翻译成达梦的元数据过程中解决类型映射、语法转换根据翻译后的定义在目标库建对象再从源库读数据按批写入目标库最后做校验比对行数和数据内容。关键点在第2步。Oracle的语法和达梦有很多相似之处但并不是100%兼容。DTS会把Oracle里常见的PL/SQL、包、触发器做一次语法转换能转的直接转转不了的就报在日志里等人工处理。这比我们手工翻译要省力得多。1.3 实际项目里怎么选什么情况必须上DTS我参与过的一个CRM系统迁移源端Oracle 11g库里有三百多张表存储过程加函数两百多个触发器六七十个。最开始有人建议用datapump导出成dmp再想办法处理。问题在于Oracle的dmp格式达梦根本不认这条路直接堵死。后来用DTS评估报告出来能自动转换的对象占了大部分需要手工干预的是几十个带特殊语法的存储过程外加若干分区表和自增列。整体工作量从预估的两周压缩到一周不到。所以我的建议很直接只要是从异构数据库往达梦迁优先考虑DTS只有少量数据、没有复杂对象的小项目才考虑手工导出导入。一个成熟的迁移工具能帮你把90%的机械劳动省下来把精力留给剩下10%需要人来判断的东西。2. DTS连接环境里的那些坑先把源端和目标端打通2.1 DTS从哪里启动以及环境准备先解决工具本身的问题。DTS随达梦数据库一起安装装好后在DM安装目录下的tool目录里。Linux环境下通常叫dtsWindows环境下叫dts.exe。有些发行版的安装包可能选项不同如果发现tool目录下没有可以回到安装包重新执行安装勾选迁移工具组件。Linux服务器上跑DTS有一点要注意它是图形界面程序需要X11环境。很多生产数据库服务器是不装图形桌面的这时候有两个办法。一是用支持X11转发的终端工具连接服务器把DISPLAY变量指到本地再启动例如export DISPLAY192.168.1.10:0.0 cd $DM_HOME/tool ./dts二是直接在一台有图形界面的Windows机器上安装达梦客户端工具用客户端连接目标达梦库。实际项目里我更推荐后者因为数据库服务器通常在内网来回转发X11的体验很一般点一下等三秒迁移大任务时还容易断。2.2 源端连接Oracle、MySQL、SQL Server都不一样DTS界面上新建工程之后第一步是选源端数据库类型然后填连接信息。不同源端的配置方式差异不小我把常用的几种写一下。先说Oracle。DTS连接Oracle一般走两种方式JDBC直连或者通过本机的ODBC数据源。JDBC直连相对省事只要本机能通过网络访问Oracle的1521端口填主机名、端口、服务名、用户名、密码就能测通。这里最常见的坑是Oracle客户端环境变量。DTS在加载JDBC驱动时有时候需要找到Oracle的安装目录比如instant client解压路径如果路径没配对报错会指向驱动加载失败但看日志又看不出来具体原因。如果走ODBC则要求本机配置好Oracle的ODBC数据源同时注意位数对齐。DTS进程是32位还是64位取决于你的达梦客户端安装版本ODBC驱动也得是同一个位数。我第一次配的时候装了64位的Oracle instant client但当时的DTS是32位进程怎么测都报“找不到Oracle客户端”折腾了小半天才反应过来。MySQL相对简单DTS里直接填JDBC连接串URL类似jdbc:mysql://ip:3306/dbname驱动一般自带。要注意的是源端账号权限至少需要SELECT、SHOW VIEW、TRIGGER这些权限否则读元数据的时候会漏对象。SQL Server也不复杂填好主机名、端口、数据库名、用户名密码即可。如果源数据库是Windows认证模式需要额外勾选对应的认证方式。2.3 目标端连接与模式映射目标端一般就是本机的达梦数据库默认端口5236用户名可以是SYSDBA。我建议在正式迁移前先创建一个专门的迁移账号比如MIG_USER给它授予需要建表、建视图、建存储过程的权限不要全程用SYSDBA。原因不是达梦限制SYSDBA迁移而是用专属账号能避免后续审计时一堆对象全都是SYSDBA创建的分不清哪些是迁移产生的。模式映射是这里容易被忽略的一步。Oracle里叫用户SCHEMA达梦里叫模式SCHEMA/MODE但迁移对象时可以选择把源库的A用户迁到目标库的B模式。比如源库是SCOTT用户目标达梦库里我希望放到APP1模式下那就在映射关系里配上SCOTT到APP1。如果不配默认是同名映射源库是什么模式目标库建什么模式。2.4 执行位置的选择网络和图形界面的取舍这条经验是用一次惨痛教训换来的。某次跨网段迁移源Oracle库在A机房目标达梦在B机房DTS跑在办公网的跳板机上。逻辑上三边网络都通但实际迁移速率只有每秒几万行。查了半天发现DTS与源库之间虽然通但延迟很高每次批次读取都要在网络上耗掉不少时间。从那之后我定了个原则执行DTS的机器网络上要尽量靠近目标达梦库。最好就在达梦服务器本机跑如果服务器没有图形界面就用数据库客户端机器跑。数据迁移是典型的高吞吐场景源端和目标端之间的每一次读取、写入都走网络跨IDC的延迟会成倍放大不要在这个环节省事。3. 结构迁移别急着勾“全选”自增列和存储过程才是重头戏3.1 迁移评估这一步不能省DTS提供了迁移评估功能正式迁移前先跑一遍评估能出一份兼容性报告。报告里会把源库每个对象标注为“兼容”“警告”“不兼容”三种状态不兼容的还会给出原因和可能需要人工处理的方向。我们项目里第一次跑评估时Oracle的分区表、部分物化视图、带DBMS_SQL的存储过程都被标了红。其中分区表是因为达梦的分区语法和Oracle有差异需要手动调整建表语句DBMS_SQL相关的代码则是因为两个数据库内置包接口不同。评估报告的价值在于它能告诉你要花多少精力在对象改造上还能预估迁移顺序。我看到有些人跳过评估直接迁移结果跑到一半存储过程全部失败又回头来排查反而更慢。3.2 模式、表空间映射与对象迁移顺序对象迁移时可以全选源库模式下的所有对象但全选不等于无脑跑。DTS支持调整对象迁移顺序这一点非常重要。对象的正确迁移顺序应该是表结构优先其次是序列然后视图、同义词接着是约束和索引最后是存储过程、函数、包、触发器。为什么这样排因为存储过程里可能引用视图和序列触发器里可能引用表如果先建触发器表上的数据还没迁触发器一触发反而是干扰。视图依赖表结构索引依赖表数据所以索引不能建太早。表空间映射也在这一步设置。Oracle里的数据可能分布在几个表空间达梦迁移时可以选择把某个源表空间映射到目标达梦的某个表空间。如果目标达梦库里还没有对应的表空间记得提前建好否则建表会失败。3.3 自增列转换触发器方案与identity的取舍Oracle实现自增的经典方案是序列加触发器比如BEFORE INSERT触发器里取NEXTVAL。达梦支持两种方式一种是保留Oracle的习惯也建序列和触发器另一种是直接用达梦的IDENTITY自增列。DTS默认可能把Oracle的序列迁移成达梦的序列触发器也照样迁移。这么处理兼容性好应用不用改但性能上有个隐蔽问题大数据量批量插入时触发器逐行调用序列开销不小而且一旦并发高序列争用也可能放大。我建议在迁移评估时留意触发器列表凡是“为自增服务的BEFORE INSERT触发器”可以跟开发确认后在目标库改成IDENTITY列。改法不复杂建表时把对应的列带上IDENTITY(1,1)然后删掉源端带过来的触发器。DTS迁移表结构时不一定会自动这么转换但目标表建好后手工改一列是可控的。如果有应用显式往自增列插入值比如数据补录场景就要小心IDENTITY的限制。达梦有SET IDENTITY_INSERT这样的开关需要先开启才能往自增列写显式值建议迁移前让开发确认一下应用有没有这类操作。3.4 存储过程、函数、包迁移的报错处理存储过程是结构迁移里最耗人工的部分没有之一。DTS会自动转换常见PL/SQL语法但遇到复杂场景时转换器也会束手无策。我遇到过的典型报错包括使用DBMS_SQL动态SQLDTS转换成达梦的对应包时参数类型不匹配存储过程里直接写了Oracle特有条件语法比如CONNECT BY虽然达梦兼容但某些分层子句的细微差异会报错使用了第三方包比如Oracle的UTL_FILE、UTL_HTTP达梦内置包接口有差异包内全局变量和游标变量的初始化方式不同。处理逻辑基本是看迁移日志定位到具体对象打开源端定义在目标端手工改写然后在达梦管理工具里单独编译验证。DTS支持对单个对象重新迁移不用整个重跑。我的习惯是先把所有失败对象列表导出来按原因归类语法兼容问题、内置包差异、依赖缺失。语法兼容的批量处理内置包差异的找开发一起评估是否需要改功能依赖缺失的检查对象顺序。分类处理后大部分对象都能救回来。4. 大数据量全量迁移的调优实录与失败重试4.1 影响全量迁移速度的几组参数DTS跑数据迁移时有几个配置项对速度影响最直接并行度、批次大小、批量提交行数、是否先建索引。并行度控制同时读几个表、往目标端写几个通道默认值往往偏保守。我在4核8G的迁移机器上一般设4到6如果源库和目标库压力都不大再往上调。但别一味贪大并行度太高会把源库的I/O打满影响源库正常业务。批次大小和批量提交行数一起看。DTS从源库读数据是按批读一次读取的行数越多网络往返越少写入目标库时按事务提交提交行数太小时事务频繁性能上不去。实测里把每次批量提交从默认的500行调到2000行速度提升经常是成倍的。4.2 一次2亿行大表的调优实录说个具体案例。有个订单归档表源库Oracle数据量约2亿行表上还有几个索引和一个大字段列。刚开始用默认参数跑了半小时进度才走了不到8%按这速度得十几个小时割接窗口根本扛不住。当时做了四件事第一把目标表上的索引先删掉数据迁移完成后再重建。索引在数据加载时每次写入都要更新开销非常大删除后写入基本是顺序追加快很多。第二把DTS的并行度从2调到6同时给该表单独指定了较大的批次行数。第三把归档模式下的日志压力降到最低。达梦在归档模式下每批提交都要写归档日志批量提交太小日志切换频繁整体就慢。第四确认源库读取是走的分批ROWID方式而不是全表扫描一次性读进内存。大表一次性读入内存容易触发JVM内存问题分批读则平稳得多。调整之后剩余数据迁移时间从预估12小时缩短到3个多小时。这个案例说明大表迁移慢往往不是工具瓶颈而是参数没给到位。4.3 LOB字段、长文本和字符集问题带CLOB、BLOB字段的表比普通表容易出问题主要卡在内存和字符集上。CLOB字段内容大时一次读入内存再写入目标库很容易撑爆DTS的JVM堆。遇到这种表把批次行数调小比如每次只读50行或100行反而比硬怼大批次快因为不用频繁触发垃圾回收。字符集问题更隐蔽。源库是ZHS16GBK目标达梦是UTF-8DTS内部会做一次字符集转换一般能转但中文里一些特殊符号比如生僻字如果在源库和目标库的字符集里都没覆盖就会变成乱码或者问号。我的经验是建达梦库时优先选择与源库兼容的字符集或者在迁移前就把目标库定为UTF-8并在DTS连接串里显式指定客户端字符集不让它去猜。迁移完成后抽查几条带生僻字、特殊标点的记录看是否原样保留。4.4 表级失败的重试和断点续传DTS跑数据迁移时整体任务是由一个个表级任务组成的。某个表失败不会导致全局回滚DTS会记录错误日志把失败原因和对应SQL打出来。失败常见原因有目标端字段长度不足导致数据截断源库某列有非法的日期值比如0000-00-00唯一约束冲突。处理方式是先修目标端的表结构或数据然后针对失败表重新迁移。已经迁移成功的表不会重复迁移这一点比很多自研迁移脚本好得多。不过我也提醒一下DTS的重跑粒度是表不是行。一个表迁到一半断了重新跑这个表时之前导入的半数数据不会自动清空如果目标表没有做分区或者清理可能出现重复数据。所以我的习惯是在重跑表任务前先手动清空该表或者确认源表的数据是全量快照而不是增量。5. 迁移完不等于结束校验和割接窗口才是验收关键5.1 DTS自带校验能做什么DTS提供了数据校验功能可以在迁移完成后对源库和目标库做行数比对也可以按条件抽样比对关键数据。界面上的操作不复杂选择要校验的表配置校验方式比如全表比对、只比对行数、或者按主键抽样然后运行。结果会列出不一致的表点进去能看到具体差异。但自带的校验有个现实问题全表数据比对在大表上耗时可能比迁移本身还久。所以实际使用中我通常对全库做行数校验对关键大表做抽样校验真正做到全表字段级比对只留给最核心的几张表。5.2 生产割接前的交叉验证清单DTS跑完后线上一旦切换发现问题再回退成本很高。所以我除了用DTS校验还会做几道额外的交叉验证。方式一是计算关键字段的聚合值。比如对流水表做SUM(金额)、COUNT(DISTINCT 用户ID)源库和目标库各跑一遍比对结果。这个验证能覆盖到行数一致但数据内容不对的场景。方式二是按主键抽样源库随机抽100条主键逐条对比这几个字段的MD5值。这类验证不用写很复杂的脚本用disql加简单SQL就能完成。方式三是业务探测SQL。拿应用里最核心的几个查询比如首页统计、订单列表直连源库和目标库各跑一遍看返回条数和关键字段是否一致。这个验证最有说服力因为最终用户感知到的就是业务SQL的结果。我每次做割接前检查都会把这三层结果整理成一张Checklist逐项打勾。DBA心里有数开发也安心。5.3 切换窗口的时间估算与回退方案迁移完成不代表可以立刻切换。实际割接窗口我通常按这个公式估算总时间 全量迁移耗时 增量数据追平时间 业务验证时间 预留20%缓冲如果业务允许停机在停业窗口前完成全量迁移窗口里只需要处理停业期间产生的增量数据。这部分增量如果不大可以手工导出导入如果业务停不了太久增量很大那就得考虑达梦的DMHS做实时同步先把增量追平再在极短窗口内完成应用切换。回退方案一定要在切换前定好。我的做法是保留源库环境至少两周应用切换到达梦后只读业务走达梦写操作业务逐步放量。一旦发现严重问题应用配置改回源库即可。两周观察期过后再关停源库环境。5.4 迁移后的运维调整数据迁到达梦之后有几项运维动作不要漏掉。第一重建统计信息。数据量变了统计信息不更新优化器可能选错执行计划。用达梦自带的DBMS_STATS或管理工具里的更新统计信息功能跑一遍。第二重建索引并更新索引统计。如果迁移时为了提速删过索引记得在迁移完成后重新创建并收集统计信息。第三检查达梦的初始化参数。比如Buffer池大小、日志缓冲区、并行度这些参数在迁移前后可能要按生产负载重新调整。源库是Oracle的话原来的一些运维经验不能照搬毕竟两个数据库的内存模型和会话管理机制不一样。第四应用侧的连接串要改成达梦的驱动和URL密码加密方式、连接池配置也需要跟着调。这一项最容易被忽略但上了生产才发现连接池建不起来是很糟心的。最后说点个人体会。DTS解决的是“能不能迁”的问题而“迁得好不好”取决于你前面花了多少时间在评估和对象改造上。别指望一个按钮把Oracle几百个包全部完美翻译成达梦语法那不现实。我们每次做迁移评估报告出来后的那两天往往是整个项目最忙的时候把不兼容对象一个个改掉后面数据迁移反而顺风顺水。希望这篇基于实际经验的内容能让你在真正碰到达梦DTS时少走几步弯路。