做MySQL到达梦数据库(DM)迁移这件事,很多人一上来就想着写脚本、打磨SQL、逐张表倒数据,一套折腾下来少说也要半天。实际上,如果你的源库表结构不复杂、数据量也不大,用对工具的话,三分钟完成迁移完全不是夸张。我最近刚帮一个业务模块做过一次这样的迁移,整个操作过程比我预想中顺利得多,所以把整个思路和踩坑点整理出来,给同样要面对这个任务的朋友做个参考。
这篇内容适合谁?简单说两类人:一类是手上正有MySQL存量库要往达梦切,但对迁移工具链不熟,想找一条最快路径的人;另一类是已经用命令行导过一次数据,结果发现自增列、字符集、约束都没处理好,想系统避坑的人。我会把“为什么能三分钟搞定”“具体按哪几步操作”“每个关键动作背后的原理是什么”“哪些坑我用真金白银踩过”都讲清楚,保证你能直接照着做。
1. 迁移前的思路拆解:为什么能三分钟完成
1.1 迁移的本质是什么
数据库迁移说白了就是做三件事:把表结构搬过去、把数据搬过去、把约束和索引补回来。听起来简单,实际很多人慢就慢在——先手动创建了达梦端的库和表,然后写一堆转换脚本,再导数据,最后发现字段类型对不上,又来回改。
如果你把“迁移”当成一次手工搬运,自然会慢。但换一种思路,当成分库分表之间的“传输任务”,让工具去处理类型映射和批量写入,事情就快多了。三分钟不是指上万张表、几十GB数据的极限操作,而是指一张或几张核心业务表、几十万行数据量级别下的真实体验。这个前提必须先说明白,否则你们按这个思路去迁移一个几百GB的大库,回头说我吹牛就不合适了。
1.2 选对工具是提速的七成因素
同样一个迁移需求,工具选错了,后面全是事。我试过几种方案,你们可以参考我的判断:
| 迁移方式 | 速度 | 适合场景 | 麻烦程度 |
|---|---|---|---|
| mysqldump 导出 + SQL 手工调整 | 慢 | 离线小库、环境隔离 | 高,SQL方言差异全靠手改 |
| 编写ETL脚本,用JDBC批量读写 | 中 | 有复杂转换逻辑、定时增量 | 高,需要开发能力 |
| 可视化客户端的“数据传输”功能 | 快 | 一次性全量迁移、结构相对简单 | 低,几乎零门槛 |
| 数据库官方专业迁移工具 | 很快 | 大批量、复杂对象、生产环境 | 中,需要熟悉工具配置 |
我最终采用的是第四种和第三种的组合:先用可视化客户端快速完成单批次结构+数据迁移,再用官方工具处理存储过程、视图这类逻辑对象。这里想强调的是,不要迷信“命令行更专业”的说法,在快速迁移这个目标下,可视化工具能帮你自动规避掉大量类型不兼容的坑,它背后的映射规则就是为你省时间的那只手。
1.3 达梦对MySQL的兼容性比很多人想的好
达梦数据库并不是一个完全陌生的“异端”,它对MySQL的常用语法做了相当多兼容处理。比如你写LIMIT、AUTO_INCREMENT、ENGINE=InnoDB这类MySQL语法,达梦很多版本都能直接接受,或者在迁移工具的帮助下自动转换成IDENTITY、INITRANS之类的达梦写法。
但兼容不等于零检查。你真正需要关注的是这么几类差异:字符串类型长度单位(MySQL的VARCHAR(255)在达梦里是字符还是字节,不同版本配置不同)、自增列的处理方式、TINYINT(1)映射成什么、DATETIME要不要转成TIMESTAMP、utf8mb4与达梦字符集的对应关系。这些细节我会在后面逐步拆开讲。三分钟能不能真正完成,就看这些点你是不是提前心里有数。
2. 三分钟快速迁移的核心实操步骤
2.1 环境准备:两个连接先跑通
先说前置条件。你本机需要安装一个支持达梦数据库连接的可视化客户端,我这里用的是常见的通用数据库客户端(Navicat类工具),同时确认MySQL和达梦两个服务都已经启动,并且你手头有这两个库的账号密码。
达梦的连接参数里有一个容易卡住人的地方:端口号。MySQL默认是3306,而达梦安装时手动或自动配置的端口通常是5236,但很多人会下意识以为是3306。连接不上时先检查端口,这是个非常低级的坑。另外,达梦的数据库驱动(JDBC驱动包)要提前在客户端的“驱动程序”里配置好,否则你连连接类型里都找不到达梦这一项。
连接配置界面里,MySQL侧就填主机、端口、用户名、密码;达梦侧除了上述信息外,还要注意“Schema”或“模式”这个概念,达梦里模式名和用户名往往是一一对应的,默认填你登录的用户名就行。两个连接都显示成功后,在左侧树形列表里能同时看到两个数据库,这才算准备完成。
2.2 一键数据传输:结构、数据一次搬完
在客户端里,你要做的其实只有几步:点中源库(MySQL)的表,选择“数据传输”或“同步到”目标库(达梦),然后在弹出的配置界面里勾选要搬的表。
这里有一个关键选项:同步结构。务必勾上。勾选后,工具会自动读取MySQL的CREATE TABLE语句,并转换成达梦能接受的建表语句。你只需要选择“仅结构”还是“结构和数据”。要做到三分钟,就选“结构和数据”,一次性搞定。
数据传输过程中的几个重要参数:
- 批量插入大小:默认可能偏保守,如果源表几十万行,可以把批量大小调到5000或10000,减少网络往返次数。
- 事务模式:小表可以每张表一个事务,大表建议关掉“使用事务”,否则中途失败回滚会非常慢。
- 数据冲突策略:一般选择“插入”,如果表已经存在,选择“删除并重新创建”可以避免重复数据问题。
点击“开始”之后,工具会在后台生成映射关系,弹出一个进度条。我在实际迁移中,一张10万行的业务表,加上结构创建,总计大约40秒完成。两三个这样的表加起来,三分钟绰绰有余。
注意:如果你迁移的表数量特别多,比如超过几百张,建议分批次勾选,不要一次性全选。因为工具默认是一张表接一张表串行执行,中途任何一张表报错都可能卡住队列。
2.3 达梦侧的表结构修正:自增列是重头戏
数据传输完成后,你以为就结束了?没那么简单。你需要到达梦库里刷新表结构,逐个检查迁移过来的表,尤其是主键和自增列。
MySQL中常见的id bigint NOT NULL AUTO_INCREMENT,工具迁移到达梦后,可能会变成普通的BIGINT列,丢失自增能力;或者变成达梦的IDENTITY,但起始值和步长不对。正确的做法是:对于业务主键,在达梦里手动重建自增列。达梦有两种自增方式:一种是IDENTITY(起始值, 步长),可以在建表时定义;另一种是通过序列加触发器实现。对于快速迁移场景,建议直接用工具提供的“修改表”功能,把主键字段改成达梦的标识列。
操作上,我通常这样操作:先查看迁移过来的表结构,如果主键列没带自增属性,就执行ALTER TABLE 表名 MODIFY id BIGINT IDENTITY(1,1);,重建主键约束。这一步非常关键,否则你的应用在插入新记录时会因为没有自增值而报错或插入失败。
2.4 索引、约束的补充与验证
工具在迁移时通常会保留主键和唯一索引,但普通索引、外键约束、默认值这些对象有时会被跳过。所以迁移完必须对比一遍源库的索引列表。
一个比较实用的做法:在MySQL侧执行SHOW INDEX FROM 表名;,手动记录下非唯一索引的名称和字段组合;到了达梦侧,用SELECT * FROM USER_INDEXES WHERE TABLE_NAME='表名';检查哪些索引没过来,缺什么补什么。
外键约束我的建议是:如果业务逻辑没有强依赖数据库层约束,可以先不迁移,改到应用层去控制。外键在数据迁移中经常造成插入顺序错误,反而拖慢速度。如果你确实需要外键,那就在数据全部导入完成后,再一次性添加,这样能避免级联关系导致的失败。
3. 迁移过程中的细节原理与参数说明
3.1 为什么小表能三分钟,大表却可能卡到天荒地老
三分钟的秘诀在于“尽可能减少对话次数”。数据库客户端传输数据时,走的也是JDBC连接,它本质上是在循环执行INSERT语句。如果一条一条插,10万行就是10万次网络往返,加上达梦每次commit都要写日志,速度自然上不去。
所以批量插入大小这个参数很关键。它决定了每次INSERT INTO ... VALUES (...),(...),(...)里封装了多少行。批量大小从1000调到5000,传输速度通常能提升4-5倍,因为网络往返次数大幅降低。我测试过,10万行数据,批量1000大约需要70秒,批量5000只需要35秒,效果立竿见影。
还有一个容易被忽略的是达梦的提交模式。部分客户端工具在数据传输时,默认每一万行或者每张表提交一次。如果源表非常大,比如几百万行,整个事务会非常长,日志文件疯涨,甚至可能触发锁等待。建议对超过50万行的表,把“同步选项”里的“每X行提交一次”勾上,比如每20000行提交一次,这样既不拖慢速度,也能控制事务大小。
3.2 字符集和排序规则:最容易乱码的地方
MySQL这块,很多老库用的是utf8mb4,也有少量库还在用latin1。达梦这边,数据库的字符集在初始化时就定了,常见的有UTF-8、GBK、GB18030。如果源库是utf8mb4,目标库是UTF-8,一般没问题;但如果目标库是GBK,而源库有生僻字、emoji,那就会丢失或乱码。
迁移前先确认一下达梦的字符集:SELECT * FROM V$INSTANCE;或查看初始化参数。如果达梦是UTF-8,通常不用额外处理。如果是GBK,建议在客户端的数据传输设置里,把“源编码”指定为UTF-8,把“目标编码”指定为GBK,让工具自动转换。
这里有一种情况非常隐蔽:MySQL连接串没指定characterEncoding,导致客户端读到的是系统默认编码,迁移过去后中文全变成“???”。解决办法是,在MySQL连接的高级属性里,显式设置characterEncoding=utf8mb4。这是我在实战中踩过最深的坑之一,你们一定要先检查连接串参数。
3.3 字段类型的映射规则速查
达梦和MySQL的有些类型长得像,但语义不同。下表是我多次迁移后整理出的映射关系,你们可以直接抄作业:
| MySQL类型 | 达梦推荐类型 | 说明 |
|---|---|---|
| TINYINT | SMALLINT | 达梦无TINYINT,工具通常自动映射 |
| TINYINT(1) | SMALLINT 或 NUMBER(1) | 如果当作布尔值用,建议用NUMBER(1)+CHECK约束 |
| INT | INT 或 INTEGER | 直接映射,注意长度显示不影响 |
| BIGINT | BIGINT | 常用作自增主键 |
| VARCHAR(n) | VARCHAR(n) | 注意达梦的n可能按字节也算字符,需一致性检查 |
| TEXT | TEXT 或 CLOB | 建议CLOB,支持更大长度 |
| BLOB | BLOB 或 IMAGE | 一般用BLOB,但需要确认JDBC驱动映射 |
| DATETIME | TIMESTAMP | 可兼容 |
| TIMESTAMP | TIMESTAMP | 注意默认值和ON UPDATE语义 |
| DECIMAL(m,d) | NUMBER(m,d) | 直接映射 |
| ENUM | VARCHAR + CHECK | 达梦无原生ENUM |
| SET | VARCHAR + CHECK 或多对多表 | 建议拆表 |
一个需要注意的点是:很多工具会自动把MySQL的TEXT映射成达梦的VARCHAR2或VARCHAR,但如果原表用的是LONGTEXT,映射成VARCHAR就可能因为长度溢出而报错。迁移完成后,手动查一下所有TEXT、LONGTEXT、MEDIUMBLOB类型的变化,该改成CLOB、BLOB就及时改。
3.4 大字段(TEXT/BLOB)传输为什么会慢、如何优化
一张表里如果有一个BLOB列,存储的是图片或文件,那传输速度会显著下降。因为BLOB数据在网络上传输时占用的带宽大,而且达梦写入大字段时通常需要特殊的批量处理,很容易触发“单条数据过大”之类的错误。
优化技巧有两个:
- 如果业务允许,第一次迁移先只迁结构和除大字段以外的列,也就是把大字段列忽略掉,等基础数据到位后再通过SQL脚本补充大字段数据。
- 如果必须一起迁,把批量插入大小调低一点,比如降到500,避免单条SQL拼接的字节数超过达梦的SQL长度限制。同时检查达梦的
MAX_LONG_VARCHAR或VARCHAR_IN_CLAUSE等参数。
我在一次迁移中处理过一张7万行的合同附件表,单个BLOB平均1MB,按初始配置跑会卡死在某个字段上。后来把批量调成200,关闭事务,用了2分钟跑完,完全能接受。
4. 常见问题与排查技巧实录
4.1 连接达梦失败:驱动没配好或端口不对
量大面广的第一个问题是客户端里根本没有达梦连接类型,或者连接时报“无法加载驱动程序”。这是因为达梦的JDBC驱动并不是客户端自带的。解决办法:去达梦的安装目录下找DmJdbcDriver或dm-jdbc相关的JAR包,在客户端“管理工具→驱动→新建驱动”里,选择JAR包,并且填写正确的类名。达梦JDBC的类名通常是dm.jdbc.driver.DmDriver,URL格式是jdbc:dm://IP:5236。如果你手头没有JAR包,也可以在达梦服务器上找,一般在安装路径的jdbc目录下。
端口问题前面说过,达梦默认5236,但有些客户为了隐蔽会改成别的端口,此时你去问DBA比一个一个试效率高得多。
4.2 迁移时报“无法识别的类型”或“类型不支持”
这种报错通常是某些特殊类型没有被工具的映射表覆盖。比如MySQL 5.7上的YEAR类型、GEOMETRY类型,或者JSON类型。达梦对JSON有支持,但你的客户端版本可能太老,不认识这个类型映射。
我的处理思路是这样的:先把报错的那张表单独勾选,在数据传输设置里找到“类型映射”或“高级映射”,手动指定MySQL的JSON转换成达梦的VARCHAR或CLOB。对于GEOMETRY这类空间数据,干脆用临时列转成二进制存BLOB,等数据迁完后再用空间函数处理。如果你的业务里完全没有这类字段,就把它们排除在迁移列表外,后续单独处理。
4.3 自增列没有生效,插入数据报主键重复
这是最容易被忽略的故障。表迁过去了,数据也在了,但你以为的大自增主键根本没有自增属性。新应用一上线,插入一行数据,报“违反唯一性约束”或者尝试插入NULL到非空列。
前面第2.3节我讲了用MODIFY加IDENTITY,这里补充一个需要注意的事项:如果迁移工具已经帮你建成了IDENTITY列,但自增的起始值是0或者1,而当前表里已有最大主键是50000,那新插入的记录可能会撞上旧值。你需要把自增起始值改成当前最大主键+1。达梦的语法大概是ALTER TABLE 表名 ALTER COLUMN id SET IDENTITY(50001, 1);,具体写法看版本。改完插入几条测试数据验证一下。
另一种方案是创建序列+触发器,适合对自增规则有特殊要求的场景,但快速迁移就没必要那么复杂了。
4.4 迁移后中文乱码,数据读出全是问号
这个前面3.2节提到过。如果乱码已经发生,先说怎么修:如果数据里是问号,可能已经不可逆了,只能重新迁移。迁移前务必做三件事——第一,MySQL连接属性里强制characterEncoding=utf8mb4;第二,达梦目标库的字符集确认是UTF-8;第三,在数据传输设置里指定源库字符集类型为UTF-8。
我在一个老项目里遇到过源库表是latin1,但里面有中文的情况。这种属于历史遗留问题,快速迁移工具无能为力,你必须先通过SQL把latin1列转换为utf8mb4。比如CONVERT(BINARY CONVERT(列名 USING latin1) USING utf8mb4)。做过这一步后再重新迁。
4.5 迁移过程中超时、中断、进度条卡住不动
常见原因有三种:网络不稳定、某个字段值触发了特殊字符问题、达梦段或表空间满了。如果进度条长时间不动,不要傻等,先看达梦的告警日志,通常能发现具体是哪个表、哪个字段出了问题。
比较有效的排查方式是把失败日志开启,让工具记录错误行。很多客户端在“数据传输”设置里有一个“错误处理”选项,可以设置成“出错继续”。这样单条数据错误不会中断整个任务,只会记录到日志文件里,跑完之后你根据日志去修复那几条脏数据就行。我们用这个办法处理过很多次脏数据导致的中断,比一行行排查高效得多。
4.6 一个真实场景的迁移过程复盘
之前某内部系统要切库,源库是一个MySQL 5.7实例,大约40张表,其中有3张超过20万行,其余都是万行级别的配置表。我用可视化客户端迁移,总计耗时大约12分钟——远超三分钟了,因为其中有几张表包含大字段,并且有几张表结构不一致需要单独映射。
但是把范围缩小到单张核心交易表后,纯结构+数据迁移,10万行,45秒跑完。我当时做了详细的计时:建表1.5秒,数据类型转换0.8秒(因为工具已经生成映射),数据写入40秒,索引创建3秒。所以“三分钟”完全不是噱头——前提是用对工具、预处理映射、批量参数调到位。凡是超过这个时间很多的项目,往往不是迁得慢,而是“试错”的时间远比“执行”的时间多。
5. 从三分钟到质量保障:迁移后的验证与优化
5.1 表数量、记录数核对:用一组SQL快速自查
不要因为工具提示成功就觉得万事大吉,一定要核对。最快速的办法是分别统计两边库里的表数量:MySQL侧SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='库名';,达梦侧SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME IS NOT NULL;(需确认视图存在性)。两边表数量一致,只能说明表的个数对得上,数据量还得逐表比对。
逐表比对数据量可以这么干:在MySQL侧把每张表导出成SELECT CONCAT('表名:', COUNT(*)) FROM 表名;的输出,达梦侧同样处理,然后用文本对比工具比对。手工一张张核对当然也行,但几十张表比对下来容易疯掉。我更推荐直接对比记录数,既然两边表结构相同,记录数一致,再抽样比对几条业务关键字段,基本能确定迁移没问题。
5.2 关键查询与索引性能初步验证
表挪过来了,不代表SQL也快。MySQL里建好的索引字段,在达梦里可能是因为类型不同导致索引失效。比如MySQL表里写VARCHAR(20),到达梦如果变成VARCHAR2(20),查询条件里传的是数字字符串,可能引发隐式转换,影响索引命中。
我的验证习惯是:把业务系统最常用的三到五条查询SQL拿出来,在达梦库里跑一遍执行计划。达梦的EXPLAIN命令可以看执行计划,重点确认有没有出现FULL TABLE SCAN,以及查询条件是否命中了索引。如果MySQL里跑了0.5秒的SQL到了达梦跑5秒,大概率就是索引没建全或者字段类型映射出了问题。这时候去调整索引或者改SQL写法,优先级高于一切。
5.3 应用连接串切换与兼容性调整
数据库迁完之后,你的应用必须改连接串。Java开发的系统通常把数据源配置放在jdbc.properties或application.yml里,改一下驱动类、连接URL、方言配置就行。
MySQL的驱动类是com.mysql.jdbc.Driver(或com.mysql.cj.jdbc.Driver),连接串是jdbc:mysql://...;达梦的驱动类是dm.jdbc.driver.DmDriver,连接串是jdbc:dm://IP:5236。如果是ORM框架,比如MyBatis,要注意数据库方言的变化。MySQL支持LIMIT分页,达梦的不同版本对LIMIT的兼容程度不一样,如果你升级到较老的达梦版本,可能得改写成TOP或ROWNUM。这个问题在迁移后测试时很容易暴露,建议提前检索代码中所有LIMIT、concat、ifnull等MySQL专属函数,一并替换。
5.4 备份与回滚策略:别把后路堵死
迁移成功后,不要立刻把MySQL库删掉。我建议至少保留MySQL数据一周,并且保留迁移那一刻的全库备份。原因很简单:新系统上线前你一定会发现几个应用层的小问题,改改达梦表可以,但如果数据类型映射导致的业务逻辑错误特别多,你可能会想“刚才没迁好,能不能重新来”。有备份,你完全可以删掉达梦库,重新建立干净的库,再来一遍三分钟迁移。
更好的方案是把达梦迁移好的库在测试环境跑一遍完整的回归测试,把涉及增删改查的用例都过一遍。尤其要验证自增插入、批量导入、报表统计这三类典型业务。等全部通过,再在维护窗口内做生产切换,这样即使出了状况,回滚成本也很低。
写在最后:关于“三分钟”的一点个人体会
我从来不为“快”而快,但这次确实体会到,很多看似麻烦的数据库迁移,其实是被流程和工具拖慢的。只要提前梳理好目标环境参数、用对传输工具、知道哪些类型需要手工修正、哪些约束需要二次补齐,三分钟完成一个中小型表单向的迁移完全没问题。
最后再分享一个我自己的习惯:每次迁移前,我会在达梦侧先创建一个“迁移审计模式”,把迁移过来的每张表记录上迁移时间、源行数、目标行数。这样一来,哪张表没迁全、哪个环节慢,回头复盘都有据可查。以上这套方法,你们在实际操作中如果有什么更好的技巧,也欢迎继续补充。