MySQL 迁移到达梦过程中遇到的一些问题记录

最近做了一次 MySQL 到达梦数据库的 DTS 迁移,整体数据量比较大,迁移过程中遇到了连接数、大表读取、超时、自增列、重复约束以及超大表无主键等问题。

这里主要记录一下实际遇到的问题和排查思路,后面再碰到类似场景可以直接参考。


1. 迁移顺序

这次没有直接把所有对象一次性全部迁过去,而是大致按照下面的顺序处理:

text 复制代码
表定义、必要的主键/唯一约束
        ↓
表数据
        ↓
普通索引、其他约束
        ↓
视图、存储过程等其他对象
        ↓
数据核对

大表比较多的情况下,不建议一开始就把所有普通索引都建好再导数据,否则数据写入过程中还需要持续维护索引,整体速度会受到影响。

MySQL 自带的系统库不在业务数据迁移范围内:

text 复制代码
information_schema
mysql
performance_schema
sys

2. AUTO_INCREMENT 列迁移报错

遇到过一张表,MySQL 源端结构类似:

sql 复制代码
id INT NOT NULL AUTO_INCREMENT

但是 id 并不是主键,只存在普通索引。

迁移表结构到达梦时出现:

text 复制代码
AUTO_INCREMENT列必须为唯一性约束的一部分

这种情况下需要注意,源端能正常存在的表结构,不代表目标端可以直接按原定义创建。

这张表后面根据实际数据确认 id 没有重复,所以在达梦侧给该字段增加了唯一约束:

sql 复制代码
ID INT AUTO_INCREMENT NOT NULL UNIQUE

再继续迁移数据。

这里不能看到自增列就直接补主键,还是要先确认源表实际约束和数据情况。


3. 主键和唯一约束重复

还有一种情况是:

text 复制代码
PRIMARY KEY(ID)

已经创建完成,后续迁移约束时 DTS 又尝试创建:

text 复制代码
UNIQUE(ID)

达梦会提示已经存在相同的唯一关键字或主键。

如果 UNIQUE 和现有主键的字段组合完全一致,可以不再重复创建。

但下面这种不能直接跳过:

text 复制代码
PRIMARY KEY(ID)
UNIQUE(ID, CODE)

因为两者约束的字段组合并不相同。


4. DTS 导致 MySQL 连接数快速增加

迁移过程中碰到过:

text 复制代码
Too many connections

可以先通过下面几个命令确认连接情况:

sql 复制代码
SHOW FULL PROCESSLIST;

SHOW VARIABLES LIKE 'max_connections';

SHOW STATUS LIKE 'Threads_connected';

SHOW STATUS LIKE 'Max_used_connections';

继续从系统连接情况排查后,发现 DTS 启动迁移时会快速建立多个到 MySQL 的连接。

所以这个问题不能只看 MySQL 当前有多少连接,还要继续确认到底是谁在创建连接。

实际处理时主要是降低 DTS 并发,例如:

text 复制代码
表任务并发降低
并发导出关闭或调低
导入并发降低
避免大量任务同时启动

尤其源端本身性能一般时,把并发开得很高不一定更快,反而容易先把连接数和源端资源打满。


5. 大表迁移很慢,先判断到底是哪一端慢

这次迁移里有不少千万级、亿级大表。

源端主要通过:

sql 复制代码
SHOW FULL PROCESSLIST;

观察当前 SQL 和执行状态。

目的端服务器使用:

bash 复制代码
vmstat 1

重点关注:

text 复制代码
us sy id wa st

现场排查时,达梦目的端 CPU 和 IO 整体压力并不明显,而 MySQL 源端部分大表即使没有明显其他查询负载,执行:

sql 复制代码
SELECT COUNT(*) FROM big_table;

也可能接近一小时。

这种情况下,排查方向就应该优先放到源端大表扫描和数据读取,而不是一直盯着目标端写入。

后面迁移大表时,我一般会同时看:

text 复制代码
DTS 当前进度
+
MySQL SHOW FULL PROCESSLIST
+
目的端 vmstat

这样比只看 DTS 界面要直观很多。


6. 超大表不建议开启"显示行数"

DTS 在分析对象时,如果开启表行数统计,可能需要到源端执行类似:

sql 复制代码
COUNT(*)

对于普通表影响不大,但是碰到几亿行、又没有合适索引的 MySQL 表,单是统计行数就可能花很长时间。

所以超大表迁移时,如果没有必须提前知道精确行数,可以关闭这类行数统计,避免正式迁移还没开始,时间先耗在 COUNT(*) 上。


7. Read timed out

后期迁移超大表时,多次遇到:

text 复制代码
Read timed out

结合 SHOW FULL PROCESSLIST 排查,发现大部分时间还是在等待源端 MySQL 返回数据。

大致可以理解为:

text 复制代码
DTS/JDBC 发起查询
        ↓
MySQL 扫描超大表
        ↓
长时间无法及时返回数据
        ↓
连接等待时间过长
        ↓
Read timed out

所以看到这个报错以后,不要第一时间只检查达梦。

至少先同时确认:

sql 复制代码
SHOW FULL PROCESSLIST;

以及目的端:

bash 复制代码
vmstat 1

如果目标端比较空闲,而源端查询长时间处于执行状态,排查方向就应该优先转向 MySQL 服务器、网络以及连接超时。


8. DTS 显示已导出、已导入不一致

迁移大表时也碰到过:

text 复制代码
已导出 > 已导入
缓存 = 0

并且界面短时间没有明显变化。

这个时候不一定代表任务已经卡死。

可能是当前批次正在目标端提交、处理事务,或者 DTS 内部正在做批次切换。

我的处理方式还是先看源端:

sql 复制代码
SHOW FULL PROCESSLIST;

如果过一会源端查询重新出现,同时 DTS 的导出、导入数字继续增长,就继续等待,不要因为界面短时间没变化直接把任务停掉。


9. 无主键、无索引超大表怎么处理

这次最后碰到的一张表比较麻烦:

text 复制代码
数据量预计亿级以上
无主键
无唯一键
无有效索引

这种表很难直接做稳定的断点分批。

一开始也考虑过:

sql 复制代码
LIMIT offset, count

但这种方式对超大表并不理想。

一方面 OFFSET 越大,后面的查询成本越高;另一方面没有稳定排序键的情况下,用 LIMIT 做迁移断点也不够可靠。

后面采用的思路是建立一张迁移中间表:

text 复制代码
原表
 ↓
中间表
 + __DTS_MIG_ID 自增主键
 ↓
DTS 分批查询
 ↓
达梦正式表

中间表增加:

sql 复制代码
__DTS_MIG_ID BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY

然后通过:

sql 复制代码
WHERE __DTS_MIG_ID BETWEEN 1 AND 10000000

进行分段。

下一批:

sql 复制代码
WHERE __DTS_MIG_ID BETWEEN 10000001 AND 20000000

以此类推。

在 DTS 列映射时,不把 __DTS_MIG_ID 映射到达梦正式表,这样辅助字段只用于迁移分片,最终业务表结构仍然保持原样。


10. 中间表方案实际也遇到了问题

实际执行时,中间表本身创建成功,但是后面的:

sql 复制代码
INSERT INTO 中间表
SELECT ...
FROM 原超大表;

运行较长时间后连接被释放,最终中间表仍然没有有效数据。

这个现象说明,中间表方案虽然可以解决后续分片问题,但是"如何把原超大表完整复制到中间表"本身也可能成为新的瓶颈。

尤其源表本身没有主键、索引和可靠的分段字段时,很难在不修改原表的前提下直接做稳定的断点复制。

目前这一步还需要继续从源端排查,重点看:

text 复制代码
MySQL 错误日志
服务端连接超时相关配置
服务器 CPU / IO / 内存情况
网络连接情况

如果只是客户端看到 Read timed out,还不能直接判断到底是连接超时、MySQL 主动断开、服务器资源问题还是网络问题,最终还是要结合源端日志确认。


11. 迁移过程中源端仍有数据写入

这次还有一个比较现实的问题:迁移过程中源端业务仍然可能继续写入数据。

对于有主键、时间字段或者明确增量字段的表,后续还可以考虑补迁。

但对于:

text 复制代码
无主键
无唯一键
无可靠时间字段

这种表,迁移完成以后很难准确判断哪些是新增、哪些被修改、哪些被删除。

如果要求最终数据严格一致,最稳妥的方式还是在切换阶段停止源端写入,再做最终迁移或核对。


12. 一些经验

这次最大的感受是,大数据量迁移不能只盯着 DTS 的进度条。

真正有用的还是把问题拆开看:

text 复制代码
源端读得快不快
↓
网络传得稳不稳
↓
DTS 连接是否正常
↓
目的端写得动不动

如果目的端 CPU、IO 都比较空闲,而 MySQL 大表查询本身就很慢,那么继续调高 DTS 并发通常意义不大。

正式环境做类似大规模迁移时,最好提前确认:

text 复制代码
源端服务器性能
源目的端网络链路
尽量减少中间网络转发
提前识别千万级、亿级大表
提前检查无主键、无索引表
确认迁移期间源端是否继续写入

很多迁移问题不一定是 DTS 本身的问题,而是到了大表阶段以后,把源端性能、表结构和网络问题一起放大了。


总结

这次迁移遇到的问题比较杂,但基本可以归成三类:

text 复制代码
结构兼容问题
连接与超时问题
超大表性能和分批问题

小表迁移通常比较顺利,真正耗时间的还是千万级、亿级大表,特别是源端没有主键和有效索引的情况。

后续再做类似迁移,我会在正式开始前先把超大表、无主键表、源端连接数和网络链路单独列出来,提前做迁移方案,而不是等 DTS 跑到最后几张表再处理。

相关推荐
Lucifer三思而后行14 小时前
Oracle SQL 优化实战:明明走了索引,SQL 还是慢?
sql·oracle
泡泡鱼(敲代码中)16 小时前
MySQL 学习笔记:DCL、函数与约束 —— 安全、效率、完整性的三板斧
开发语言·笔记·sql·学习·mysql·gitee
润乾软件19 小时前
SQLazy: 在分组内搜索指定偏移量的相邻记录
sql·sqlazy
隔窗听雨眠1 天前
SQL分页优化深度实战:从深分页性能瓶颈到等价改写完整方案
sql·sql优化
旺仔不是程序员1 天前
判断存在用 LIMIT 1:PostgreSQL 五种 count 计数方式与 NULL 语义
数据库·后端·sql
旺仔不是程序员1 天前
IN 操作规范:PostgreSQL 元素数量、EXISTS 替代与 = ANY 写法
数据库·后端·sql
这个DBA有点耶1 天前
异构数据集成方案:跨平台同步的完整指南与工具选型(含实测)
数据库·sql·程序人生·架构·数据库架构·dba
bbq粉刷匠1 天前
04-存储过程(下):游标、异常处理与存储函数
sql
念何架构之路1 天前
beego ORM 源码(下):SQL 生成与方言
数据库·sql·beego