1. 迁移前的摸底:先搞清楚要搬什么、有什么雷
接手一个MySQL迁达梦的活儿,大多数人第一反应是找个工具直接导数据。但真实项目里,真正耗时间的从来不是数据搬运,而是SQL方言差异、数据类型兼容、驱动适配这些藏在后面的问题。我做过一次近两百张表的迁移,前面两天看着工具跑得飞快,后面两周全在改应用层SQL。所以先泼盆冷水:迁移的成败在导数据之前就已经决定了,准备工作做得越细,后面切换那晚就越轻松。
1.1 盘点实例信息:库表清单、字符集、存储引擎与分区表
第一步不是写迁移脚本,而是把源端MySQL的家底摸清楚。别只拿一条select count(*) from information_schema.tables就完事,要按维度拆开看:
- 库表清单与依赖关系:哪些表是主表、哪些是日志表、哪些是字典表,外键关系有多少层。依赖关系会影响迁移顺序,先迁主表、再迁子表,否则外键约束会卡住导入。
- 字符集与排序规则:源库如果用了
utf8mb4_0900_ai_ci这类新版排序规则,达梦不一定认识。建议统一规划目标端字符集,一般初始化为UTF-8,迁移时字符串类型按字节长度重新估算。 - 存储引擎差异:MySQL的InnoDB和MyISAM在锁粒度、事务支持上差别很大,达梦统一使用类似Oracle的表结构。MyISAM表迁到达梦后会获得事务能力,但代价是之前没注意到的隐式提交逻辑要重新审视。
- 分区表:这是容易埋雷的地方。MySQL的RANGE、LIST、HASH分区,达梦都支持,但迁移工具未必能自动转换分区定义。最稳的做法是手动创建目标端分区表,再通过工具只导数据。
- 自增列、默认值、大字段:
AUTO_INCREMENT要对应达梦的IDENTITY,DEFAULT CURRENT_TIMESTAMP要改成DEFAULT SYSDATE,TEXT/JSON要映射为CLOB。这些在数据导入时不会报错,但在应用写入时可能出问题。
1.2 静态扫描SQL风险点:关键字冲突与方言语法
光看表结构还不够,SQL语句才是迁移中最容易出现兼容性问题的环节。建议在迁移前做一次全面的SQL扫描,重点检查以下几类:
- 视图、触发器、函数、存储过程:从
information_schema里把定义全部导出来,逐个过一遍。MySQL的存储过程语法和达梦差异非常大,后面会有专门章节讲。 - 关键字冲突:达梦的保留字集合和MySQL不一样,MySQL里合法的列名
comment、level、rank在达梦里可能直接报错。这类问题静态扫描时就能发现,早期改掉比迁移后改应用成本低得多。 - 隐式类型转换:MySQL对
WHERE varchar_col = 123这种写法很宽容,达梦的隐式转换规则更严格,可能导致索引失效甚至报错。静态扫描时如果看到这种写法,直接标记为高危项。 - 方言函数与语法:
DATE_FORMAT、GROUP_CONCAT、ON DUPLICATE KEY UPDATE、REPLACE INTO这些MySQL特色语法,达梦原生不兼容,需要逐一确认改写方案。
我做迁移项目时,会把扫描结果按P0/P1/P2分级,P0是必须改的语法错误,P1是需改写但结果可等价,P2是性能隐患。这样开发团队的改造工作量可以直接估算出来,后续排期也心里有数。
1.3 数据类型映射表:从MySQL到达梦的对照策略
数据类型的映射不能只靠迁移工具自动完成,工具生成的建表语句往往偏保守,比如把VARCHAR(255)变成VARCHAR(1000),虽然功能没错,但存储空间浪费严重。下面是我在实际项目中验证过的映射方案:
| MySQL类型 | 达梦类型 | 注意事项 |
|---|---|---|
| TINYINT | TINYINT | 布尔语义可用BIT或TINYINT+CHECK |
| SMALLINT | SMALLINT | 无特殊处理 |
| INT / INTEGER | INT | 无特殊处理 |
| BIGINT | BIGINT | 无特殊处理 |
| DECIMAL(p,s) | DECIMAL(p,s) | 精度和标度保持一致 |
| FLOAT / DOUBLE | FLOAT / DOUBLE | 注意浮点精度问题 |
| CHAR(n) | CHAR(n) | 字节长度与字符长度需确认 |
| VARCHAR(n) | VARCHAR(n) | 如果n按字符算,注意达梦按字节上限 |
| TEXT | CLOB | 达梦CLOB支持较完善 |
| LONGTEXT | CLOB | 同上 |
| BLOB / LONGBLOB | BLOB | 二进制大对象直接对应 |
| VARBINARY | VARBINARY | 二进制变长类型 |
| DATE | DATE | 只存日期 |
| DATETIME | TIMESTAMP | 达梦没有DATETIME,用TIMESTAMP |
| TIMESTAMP | TIMESTAMP | 注意默认值和精度 |
| TIME | TIME | 只存时间,达梦支持 |
| YEAR | INT | 用SMALLINT或INT替代 |
| ENUM | VARCHAR(n) + CHECK | 最稳妥,应用层也能处理 |
| SET | VARCHAR(n) | 应用层拆解,不建议保留SET语义 |
| JSON | CLOB | 应用层解析,或用达梦新版本的JSON类型 |
这里特别提醒两点。第一,TEXT映射成CLOB后,有些应用会拿CLOB字段做ORDER BY或GROUP BY,达梦里对CLOB的直接排序有限制,需要改写SQL或用DBMS_LOB处理。第二,MySQL的TIMESTAMP范围到2038年,达梦的范围更大,迁移后如果应用有日期边界判断逻辑,也可能出现行为不一致,属于隐藏坑。
1.4 迁移范围与验收口径:提前定义怎么算"迁完"
很多人迁完数据就宣布完成,结果上线两天发现某个历史报表没迁、某个临时表被应用重建了,搞得焦头烂额。迁移范围必须提前用清单锁定。
我习惯做一个迁移范围确认表,包含四列:库/表名、迁移类型(全量、只结构、不迁)、源端负责人、目标端负责人。全量迁移的表包括核心业务表、配置表、历史数据表;只结构的通常是临时表、缓存表,应用启动时自己会初始化;不迁的基本是日志中间表或已经废弃的表。
验收口径也要提前定义。我的标准做法是三层:
- 行数一致:每张表
count(*)对得上,这是底线。 - 抽样字段一致:按主键抽样若干条,逐字段比对,重点看金额、时间、状态这类高价值字段。
- 关键查询结果一致:把线上真实运行的Top SQL拿出来,在达梦环境跑一遍,结果集和MySQL对比。
迁移范围确认表一定要让应用开发和业务方签字确认,否则上线后一句"这个报表当时没说要迁"就能让整个项目延期。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迁移工具选型:DTS、DataX、手工脚本怎么选
工具选型没有标准答案,取决于数据量、表结构复杂度、团队对达梦的熟悉程度。我把主流方案都过一遍,说清楚各自的适用边界和坑。
2.1 达梦自带DTS的优劣势
达梦管理工具(DM Management Tool)自带数据迁移工具DTS,支持从MySQL、Oracle、SQL Server等数据库直接迁移到达梦。DTS最大的优势是集成度高,能自动完成建表语句转换,不用自己写类型映射规则。
实际操作中,DTS走的是JDBC连接源端MySQL,所以源端最好提前建好只读账号。迁移步骤基本是:创建迁移工程 -> 配置源端MySQL连接 -> 配置目标端达梦连接 -> 选择要迁移的库表 -> 执行迁移。
DTS的适用场景是中小型数据库、表结构不太复杂、没有大量存储过程和自定义函数的项目。它的问题也很明显:一是速度一般,大批量数据导入时需要手动调批量大小;二是自动生成的建表语句有时会过度转换,比如把DATETIME变成DATE导致时间精度丢失;三是遇到分区表、自增列、特殊注释时容易出错。
2.2 DataX做异构同步的取舍
DataX是阿里开源的异构数据同步工具,通过插件机制支持各种数据源。在迁移场景下,用mysqlreader加dmwriter就能完成从MySQL到达梦的批量数据同步。相比DTS,DataX的并发控制更灵活,适合大表、千万级以上的数据量。
一个典型的DataX任务JSON大概长这样:
json复制{
"job": {
"content": [
{
"reader": {
"name": "mysqlreader",
"parameter": {
"username": "root",
"password": "xxx",
"column": ["*"],
"splitPk": "id",
"connection": [
{
"table": ["orders"],
"jdbcUrl": ["jdbc:mysql://192.168.1.10:3306/business"]
}
]
}
},
"writer": {
"name": "dmwriter",
"parameter": {
"username": "SYSDBA",
"password": "xxx",
"column": ["*"],
"preSql": ["truncate table orders"],
"connection": [
{
"jdbcUrl": "jdbc:dm://192.168.1.20:5236",
"table": ["orders"]
}
]
}
}
}
],
"setting": {
"speed": {
"channel": 8
}
}
}
}
这里有个细节:dmwriter的preSql支持在导入前执行清理语句,对可重跑的迁移非常有用。channel参数控制并发通道数,建议根据源端和目标端的IO能力动态调整,不要盲目开到32,否则容易把数据库连接数打满。
DataX的短板在于类型映射和特殊字符处理都需要手动维护,如果表数量多、字段杂,配置文件的维护成本会偏高。
2.3 纯SQL脚本迁移:什么时候用
有些场景工具反而多余。比如数据量在几十万以内、表结构非常简单、一次性迁移的测试环境,直接用mysqldump导出SQL文本,再经过批量文本替换导入达梦,效率最高。
步骤通常是这样:
- 用
mysqldump导出表结构和数据,只导出数据可以加--no-create-info。 - 写个脚本做文本替换:把
AUTO_INCREMENT替换为IDENTITY(1,1),把反引号去掉,把ENGINE=InnoDB之类的建表属性删掉。 - 在达梦里执行替换后的SQL文件。
纯SQL脚本的优点是透明可控,出了问题直接改文本重跑;缺点是没有类型映射、没有断点续跑,遇到一条坏数据整个文件就中断。所以只适合小规模、低风险的场景。
2.4 我的选型建议:混合策略
我的习惯是一张图拆三块:表结构用DTS自动转换后人工review,数据全量用DataX跑并发,特殊表(大字段多、分区表、自增列复杂)用手工SQL单独处理。如果业务对停机时间要求苛刻,迁移后还有增量数据要补,可以在达梦侧开启CDC,配合SeaTunnel这类同步组件做增量拉取,形成全量+增量的完整链路。
另外补充一点现场经验:达梦数据库安装完后,建议把官方自带的客户端工具装上,比如在麒麟这类国产操作系统上安装达梦客户端时,注意JDK版本和JAVA_HOME环境变量要配好,否则管理工具打不开,迁移工具也就无从谈起。
3. 迁移实操:结构、数据、校验三步走
工具选好了,接下来就是按步骤动手。这一章我按真实项目的操作顺序写,每步都说明为什么这样做,免得读者照搬时碰到问题不知道从哪里调。
3.1 建库建模式与用户权限
达梦的逻辑结构和MySQL差异很大。MySQL里database就是隔离单位,达梦里则是"用户即模式",创建用户的同时会创建一个同名的SCHEMA(模式),表、视图、存储过程都挂在模式下面。所以迁移前要先规划:每个业务库对应达梦的一个用户,还是一个用户下建多个模式?
我的建议是一个业务系统一个用户,这样权限管控最清晰。创建用户的SQL大致是:
sql复制CREATE USER app_user IDENTIFIED BY "Password123";
GRANT RESOURCE TO app_user;
GRANT PUBLIC TO app_user;
RESOURCE角色包含建表、建视图、写存储过程的基础权限,对普通业务用户足够。不要动不动就授权SYSDBA权限给应用账号,达梦的DBA权限比MySQL的root威力大得多,误操作风险太高。
创建完用户后,把表结构脚本在目标端执行。这里要注意模式名引用:达梦中跨模式访问表要写模式名.表名,迁移工具生成的目标SQL通常会带上模式名前缀,如果应用连接用的用户和表所属模式不是同一个,后续SQL要格外小心。
3.2 结构调整与索引策略:先建表,后建索引
这个顺序非常重要。很多人在MySQL里导完表结构,顺手就把索引、外键、触发器全建好了,结果数据导入速度惨不忍睹。因为每插一行数据,所有索引都要同步维护,外键约束还要逐行校验。
正确的顺序是:
- 先只建表结构,主键可以保留,但非唯一索引、联合索引、外键约束全部延后。
- 数据导入完成,抽样校验通过后,再批量创建索引和外键。
- 触发器在数据导入前不要建,否则导入过程会触发业务逻辑,可能导致数据错乱。
这个建议和Oracle DBA的习惯一致。数据量上百万时,先导数据再建索引比带着索引导入能快3到5倍。最夸张的一次,我见过一张2000万行的表,带索引导入跑了7个小时,去掉索引后导入只要40分钟,建索引花了15分钟,净省6个小时。
3.3 数据搬运的参数调优:批量大小、并发度与约束开关
用DataX或者DTS导入时,有几个参数直接决定速度和稳定性。
第一是批量大小。DataX的batchSize控制每次写入的行数,默认值偏保守,我一般调到2000到5000之间。目标端达梦的JDBC驱动对批量提交支持得不错,批量太大反而容易引起锁竞争,这个值需要实测调整。
第二是并发通道数。channel为4到8比较稳妥,能把多个表的导入并行起来,又不会把数据库的连接数打爆。如果源端是MySQL生产库,并发太高会占用源库大量IO,影响线上业务,事前要和DBA确认。
第三是约束和触发器。导入期间把外键约束禁用,导完再启用。达梦可以通过ALTER TABLE xxx DISABLE CONSTRAINT暂时关闭,但批量操作时最有效的还是把外键相关的语句整体延后执行。
还有几个达梦侧参数值得关注。dm.ini里的BUFFER大小影响数据页缓存,导入大表时适当调大可以提升写入速度。如果数据库开启了归档日志,导入高峰期会产生大量归档文件,磁盘空间要留足。测试环境甚至可以临时切到非归档模式,但生产环境务必保持归档,不能为了速度牺牲恢复能力。
3.4 三层校验:行数、抽样字段、关键查询
数据导完后别急着宣布成功,校验才是迁移质量的核心。我按三层执行:
第一层,行数校验。对每张表分别执行count(*),源端MySQL和目标端达梦的结果必须一致。不一致时先看是不是有NULL值的计数差异,或者特殊字符导致数据被过滤。如果只有个别表对不上,可以单独重导这几张表。
第二层,抽样校验。按主键或者更新时间字段随机抽取10到20条记录,逐字段对比值。重点看三块:一是金额、百分比这类数值字段的精度是否一致;二是时间字段的时区和格式是否被转换过;三是大字段内容是否完整,CLOB/BLOB最容易截断。
第三层,关键查询比对。从应用的真实SQL里挑出Top 10最常用的查询语句,分别在两个库执行,对比结果集。这层校验能直接暴露索引缺失、隐式转换、函数不兼容的问题,比前两层更能反映线上真实情况。
3.5 回滚窗口与增量同步
如果对停机时间有要求,迁移不可能一次性把全量数据搬完就切换。通常采用"全量+增量"的方式:先在业务低峰期做全量导入,然后开启增量同步,把从全量时刻到切换时刻之间的变更数据补到达梦。
达梦侧开启CDC后,外部同步组件可以拉取增量日志。比如SeaTunnel有达梦CDC的连接器配置,订阅数据变更并写入目标端。没有这类组件时,也可以用应用层方案:在MySQL侧开启binlog,写脚本解析并重放到达梦。但后者复杂度高,只建议在增量窗口很短、变更量很小的情况下使用。
回滚预案必须有。迁移前把MySQL源库完整备份留底,切换后如果发现严重问题,DBA可以通过备份把业务回切到MySQL。回切本身不难,难的是回切期间的增量数据要双写或者重放,这部分逻辑要提前演练。
4. 搬完只是开始:SQL兼容、驱动与应用改造
数据搬过去只是第一步,应用能正常跑起来才算真正完成。这个阶段遇到的坑往往比迁移本身更多,我挑最常踩的说。
4.1 连接信息与驱动清单:换个数据库,先从连接改起
应用连接数据库的方式要整体切换。MySQL和达梦的连接参数差别如下:
| 项目 | MySQL | 达梦 |
|---|---|---|
| 默认端口 | 3306 | 5236 |
| JDBC URL | jdbc:mysql://host:3306/db |
jdbc:dm://host:5236 |
| JDBC驱动类 | com.mysql.cj.jdbc.Driver |
dm.jdbc.driver.DmDriver |
| C#/.NET驱动 | MySql.Data / MySqlConnector | DmProvider |
| Python驱动 | pymysql / mysql-connector-python | dmPython |
| ORM方言 | Hibernate MySQLDialect | Hibernate DmDialect |
Java项目最常见的坑是JDBC驱动版本太旧,达梦官方驱动在dm.jdbc.driver.DmDriver下,但不同版本的达梦dm.jdbc.driver.DmDriver内部实现有差异,生产环境建议从达梦官方镜像仓库拉取对应版本。
配置连接池时也要注意。Druid连接池需要显式设置dbType=dm,否则连接池的SQL检测和参数设置可能不生效。Spring Boot项目还要检查validation-query,达梦上推荐用SELECT 1,不要沿用MySQL的SELECT 1 FROM dual(达梦也支持dual表,但写法上统一更好)。
4.2 SQL语法差异对照:改完这些,大多数业务SQL就通了
这是最核心的改造工作。我把高频差异整理成对照表,方便开发直接参考:
| 场景 | MySQL写法 | 达梦推荐写法 |
|---|---|---|
| 分页 | LIMIT 10, 20 |
LIMIT 20 OFFSET 10 或用 ROW_NUMBER() |
| 自增列 | id INT AUTO_INCREMENT |
id INT IDENTITY(1,1) |
| 空值处理 | IFNULL(col, 0) |
NVL(col, 0) |
| 当前时间 | NOW() / CURRENT_TIMESTAMP |
SYSDATE |
| 日期格式化 | DATE_FORMAT(col, '%Y-%m-%d') |
TO_CHAR(col, 'YYYY-MM-DD') |
| 字符串连接 | CONCAT(a, b) |
CONCAT(a, b) 或 a || b |
| 更新冲突 | INSERT ... ON DUPLICATE KEY UPDATE |
MERGE INTO ... USING ... WHEN MATCHED THEN UPDATE |
| 替换写入 | REPLACE INTO ... |
先DELETE再INSERT,或MERGE |
| 批量插多行 | INSERT INTO t VALUES (...),(...) |
达梦兼容,但建议用批量参数 |
| 正则匹配 | REGEXP |
REGEXP_LIKE |
| 布尔类型 | WHERE flag = false |
用0/1或BIT,避免布尔歧义 |
分页这个点要单独强调。新版达梦兼容LIMIT ... OFFSET语法,但如果你在达梦初始化时选了Oracle兼容模式,这套写法未必好使。为了保险,复杂的分页查询我建议直接用ROW_NUMBER() OVER (ORDER BY ...)包一层来写,通用性最强。
ON DUPLICATE KEY UPDATE建议统一改成MERGE。虽然达梦在某些兼容模式下也支持这个语法,但项目里多个环境配置一旦不一致,线上就会报语法错误。用MERGE是Oracle系数据库的标准做法,跨版本最稳。
还有一个高频改动:字符串拼接。MySQL里||默认是逻辑或,字符串拼接必须用CONCAT函数。达梦默认兼容Oracle语法,||就是字符串连接。两边的代码习惯完全不同,团队里如果同时维护两套数据库,我建议统一写CONCAT,避免语义歧义。
4.3 框架与中间件适配:MyBatis、Hibernate、Druid
Java后端最常见的组合是MyBatis/MyBatis-Plus + Druid + Spring Boot。切换到达梦后,ORM框架的方言配置要动。
MyBatis本身不强制方言,但分页插件PageHelper需要指定数据库类型。如果分页插件没有内置达梦类型,需要自定义Dialect,或者把分页SQL改成手写ROW_NUMBER()。MyBatis-Plus相对好一些,新版内置了达梦方言支持,生成的主键策略和分页语句都能识别。
JPA/Hibernate项目需要显式指定Hibernate方言为org.hibernate.dialect.DmDialect,否则Hibernate自动建表时会生成MySQL语法。配置方式如下:
yaml复制spring:
jpa:
database-platform: org.hibernate.dialect.DmDialect
Druid连接池的dbType要配置为dm,这样Druid的SQL防火墙和监控面板才能正确解析达梦SQL。如果不配置,Druid会把达梦当作MySQL解析,某些SQL语句会被误判成语法错误。
4.4 存储过程与触发器改造:工作量最大的隐藏项
存储过程和触发器是迁移中最容易被低估的部分。MySQL的存储过程语法和达梦(更像Oracle PL/SQL)差异非常大,基本不能自动转换。
举几个高频差异点:
- 变量声明:MySQL在
BEGIN内任意位置声明,达梦要求变量集中声明在DECLARE/IS区域。 - 游标:MySQL的游标语法简洁,达梦的游标更接近Oracle,需要
CURSOR ... IS SELECT ...,打开、关闭循环方式也不同。 - 异常处理:MySQL用
DECLARE CONTINUE HANDLER FOR ...,达梦用EXCEPTION WHEN ... THEN,异常类型体系完全不同。 - 存储函数返回值:达梦对函数返回值类型要求更严格,
RETURN语句的位置也有约束。 - 触发器事件和引用:MySQL用
NEW.col、OLD.col,达梦也类似,但触发器内的自治事务、变异表处理逻辑都要改写。
以我接触过的项目来看,存储过程和触发器的改造工作量通常占整个应用改造的三成以上。如果一个MySQL实例里有几十个存储过程,建议先评估业务是否真的依赖它们,有些逻辑完全可以用应用层代码代替,反而更利于维护。不是所有逻辑都有必要在数据库层实现。
5. 迁移后的报错现场:几个典型问题的完整排查过程
最后写几个我在迁移过程中真正遇到过的报错和排查思路。问题不算罕见,但排查方法值得借鉴。
5.1 迁移工具报 -6602 的定位链路
用DTS导数据时突然报[-6602]错误码,后面跟着一段文字描述。这类错误码本身没有通用含义,关键是要看错误码后面的完整文本,以及它挂在哪个对象上。
我当时遇到的情况是:某张业务表迁移到一半中断,报错提示违反唯一约束,但源端数据我在MySQL里查过,没有重复值。排查过程是这样:
- 先拿到报错时刻的写入SQL和目标表名称,确认卡在哪一步。
- 对比源端和目标端表结构,发现目标端把
VARCHAR(100)转换成了VARCHAR(300),但唯一索引定义没有完整迁移。 - 深入一看,问题出在字符集差异上:源端MySQL是大小写不敏感排序规则,达梦默认大小写敏感,源端只在小写/大小写混合上有唯一差异的数据,在达梦里却触发了唯一冲突。
- 解决方案是调整列级排序规则,或者将涉及唯一约束的列统一为小写存储后再导入。
这个案例说明,错误码只是线索,真正的根因往往藏在字符集、排序规则、约束定义这些容易被忽略的地方。如果报错信息不够明确,可以在达梦的日志目录查dm_<实例名>_<日期>.log,定位到具体SQL。服务端在极端情况下产生core文件的话,可以用达梦提供的bt命令查看调用栈,还原崩溃前的SQL执行上下文。
5.2 连接认证协议不兼容:老应用连不上新库
MySQL 8.0默认的认证插件是caching_sha2_password,很多老版本驱动不认,连接时报Firedac phys mysql client does not support authentication protocol requested这类错误。这个报错本身说的是MySQL端认证协议,但在迁移项目里我遇到过两种场景。
第一种场景:应用还没迁移,只是DTS或DataX连MySQL源库时报错。解决办法是在MySQL侧给迁移专用账号指定mysql_native_password认证方式,或者升级DataX的MySQL驱动。
第二种场景:应用切到达梦后,连接时报驱动不支持某种认证方式或加密协议。达梦JDBC驱动的版本差异会导致这类问题,尤其项目里如果之前用的是某个兼容包的旧版本。排查时先确认驱动版本是否与达梦服务端版本匹配,再看dm.ini里有没有开启额外的认证策略。驱动版本的匹配问题,官方文档里写得很明确,升级到对应大版本的驱动基本能解决。
5.3 时间字段与字符串比较的隐式转换
源端MySQL里有一条查询:
sql复制SELECT * FROM orders WHERE create_time = '2024-01-01 00:00:00';
MySQL的优化器会自动把字符串转成时间类型,配合索引可以走范围扫描。到达梦之后,如果create_time是TIMESTAMP类型,达梦的隐式转换规则不同,这条SQL可能直接做全表扫描,甚至因为精度差异查不到数据。
排查方法是执行EXPLAIN看执行计划,如果发现convert相关的全表扫描操作,就要把SQL改成显式转换:
sql复制SELECT * FROM orders WHERE create_time = TO_TIMESTAMP('2024-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS');
这类问题在代码里批量出现的频率很高,静态扫描阶段就应该标记出来,要求开发统一改成显式转换。
5.4 大批量导入慢:别急着加并发
导2000万行的表,DataX的channel从4调到16,速度反而下降,甚至报锁等待超时。这个现象在迁移项目里出现过很多次。
排查发现瓶颈不在源端读取,而在目标端达梦的写入链路。达梦在高并发写入时,日志缓冲区、数据页缓冲区、检查点触发频率都会影响性能。此时不是无脑加并发,而是要做三件事:
- 导入前把非唯一索引和外键全部延后创建,减少同步维护开销。
- 暂时调大
dm.ini里的BUFFER参数,让数据页缓存容纳更多热数据。 - 控制并发通道在4到6之间,实测这个区间写入性能最稳定。
如果做了这些优化速度还是上不去,再看源端MySQL的IO能力。DataX的channel数同时受源端和目标端约束,单方面调高没意义。
5.5 分区表迁移后丢失分区
用DTS迁移一张MySQL分区表时,目标端建表语句没带分区定义,工具默认只导了普通表结构,导致后续分区裁剪逻辑全失效。这类问题在迁移工具的日志里不一定有明显报错,只有跑真实业务查询时才会发现性能异常。
排查方法是在迁移完成后,立即对比源端和目标端的DDL。我习惯写一个对比脚本,把information_schema里的分区定义、索引定义、约束定义全部导出,和目标端达梦的DBA_TAB_PARTITIONS、DBA_INDEXES等系统视图做差异比对。分区表、自增列、默认值这三类最容易在工具转换中丢失,必须人工确认。
迁移工作结束后,我再补一句个人体会:这类国产化数据库替换项目,真正决定成败的不是工具本身,而是评估、验证和适配的细致程度。迁移只是开始,后续的备份策略、监控告警、SQL规范化都要按新数据库的特性重新梳理。如果你手上也有类似项目,建议先拿一套完整的数据在测试环境做一次端到端演练,把上面提到的坑都踩一遍,生产切换时才会真的轻松。
