navicat「数据同步」因客户端全表比对设计导致卡死,应改用分片哈希校验:按主键切片、服务端聚合md5、逐片比对count与哈希值,确保高效可信。

直接用「数据同步」功能会卡死或超时
Navicat 的「数据同步」工具默认尝试全表比对,当两个表都超过百万行、字段含 TEXT/BLOB 或存在长字符串索引时,内存占用飙升,界面无响应,甚至触发 Windows 的“已停止工作”弹窗。这不是配置问题,是设计限制——它把差异计算逻辑放在客户端本地做,没走服务端 SQL 聚合。
实操建议:
- 立刻中止正在运行的「数据同步」任务(右上角 × 不够,要进 Windows 任务管理器结束
navicat.exe进程) - 改用「查询」+「分页校验」组合:在两个库分别执行带
LIMIT和ORDER BY的聚合校验语句,比如SELECT MD5(CONCAT_WS('|', col1, col2, col3)), COUNT(*) FROM table_name GROUP BY MD5(CONCAT_WS('|', col1, col2, col3)) ORDER BY 1 LIMIT 1000 - 导出结果为 CSV 后用命令行工具比对(如 PowerShell 的
Compare-Object或 Linux 的diff -u),避开 Excel 行数上限和内存瓶颈
用「数据传输」选「仅结构」反而暴露数据不一致
很多人误以为勾选「仅结构」能跳过数据比对,结果发现目标库报错:ERROR 1062 (23000): Duplicate entry 'xxx' for key 'PRIMARY'。这是因为「数据传输」在「仅结构」模式下仍会读取源表的 AUTO_INCREMENT 值并写入目标表定义,如果两边主键值范围已重叠(比如 MySQL 源表自增到 500 万,Oracle 目标表从 1 开始),后续插入就会冲突——这本身已是数据不一致的信号。
实操建议:
- 检查两边表的主键最大值:MySQL 执行
SELECT MAX(id) FROM table_name,Oracle 执行SELECT MAX(id) FROM table_name(注意 Oracle 无 LIMIT,加WHERE ROWNUM = 1无效,要用FETCH FIRST 1 ROWS ONLY) - 若差值 > 10%,说明已有明显数据偏移,不能依赖结构同步掩盖问题
- 禁用「Auto-increment value」继承选项(在「数据传输」高级设置里取消勾选),强制目标表从 1 开始,再人工补数据
手动写 SQL 校验时,ORDER BY 必须显式指定
直接用 SELECT * FROM t1 LIMIT 1000 和 SELECT * FROM t2 LIMIT 1000 导出对比,大概率漏掉差异——因为无 ORDER BY 时,MySQL 和 Oracle 返回顺序完全不可控,同一查询多次执行结果都可能不同。你比的不是“相同位置的行”,而是“随机抽样”,毫无意义。
实操建议:
- 所有校验 SQL 必须带确定性排序:优先用主键
ORDER BY id,无主键则用所有非空字段拼接ORDER BY col1, col2, col3 - 避免用
SELECT *:TEXT/BLOB 字段会导致ORDER BY失效(MySQL 报ERROR 1055),明确列出需要比对的列 - 跨库比对时,统一用小写字段名(Oracle 默认大写,MySQL 默认小写),否则导出 CSV 后列顺序错位
真正有效的局部比对,靠三步切片 + 哈希
对超大表,不要追求“找出全部差异”,先确认“是否存在差异”。用哈希切片法,10 分钟内可完成千万级表的可信校验。
实操步骤:
- 将表按主键范围切为 100 片:例如
id BETWEEN 1 AND 10000、id BETWEEN 10001 AND 20000… - 每片执行聚合哈希:MySQL 用
SELECT COUNT(*), MD5(GROUP_CONCAT(MD5(CONCAT_WS('|', col1, col2)) ORDER BY id SEPARATOR '')) FROM t WHERE id BETWEEN ? AND ?;Oracle 改用LISTAGG+STANDARD_HASH - 逐片比对两库返回的
COUNT和哈希值,任一不等即定位到具体分片,再对该分片做行级比对
这个方法绕开了 Navicat 的 UI 层瓶颈,把计算压给数据库服务器,且结果可复现——下次跑同一片,哈希值不变。最容易被忽略的是:切片边界必须严格对齐,MySQL 的 BETWEEN 包含端点,Oracle 的 AND 条件也要保持同样语义,否则一片漏查,整个校验失效。











