pg2mysql无法零丢失因无实时变更捕获能力,存在停机窗口数据遗漏;DataGrip通过手动控制停写与增量导出逼近零丢失;真正可控方案需结合逻辑复制补丁持续同步增量。

做不到零数据丢失,但可以做到业务感知不到丢失——关键在「停机窗口控制」和「增量同步兜底」。
为什么 pg2mysql 不能保证零丢失
pg2mysql 是全量迁移工具,它不捕获源库的实时变更。只要迁移过程不是原子操作,中间就存在时间窗口:迁移开始后、迁移结束前写入的数据,会被漏掉。
常见错误现象:pg2mysql -c config.yml migrate 执行完,发现最后几分钟的订单记录没进 MySQL;--truncate 模式下更危险,清空目标表到首行写入之间,服务查不到任何数据。
- 它没有 WAL 日志解析能力,无法像
pgloader(用于 MySQL→PG)或Debezium那样订阅变更流 - 验证命令
validate只比对快照,不校验迁移期间的 DML - 不支持目标端触发器、外键约束自动禁用,容易因约束失败中断写入
DataGrip 迁移如何逼近“零丢失”
DataGrip 的「迁移数据」功能本身仍是快照式,但它提供了手动控制节奏的能力,适合有明确停机窗口的场景。
使用场景:允许 10–30 分钟停写,且能接受应用层短暂只读。
- 先用 DataGrip 导出结构(含索引、主键),手动在 MySQL 中创建空表,关闭
FOREIGN_KEY_CHECKS和UNIQUE_CHECKS - 执行第一次全量迁移(此时源库仍可写)
- 暂停应用写入,记下 PostgreSQL 当前
pg_wal_lsn()或SELECT now()时间戳 - 用
pg_dump --inserts --no-owner --no-privileges -t table_name导出停写后的增量,并手动导入 MySQL - 恢复写入前,用
COUNT(*)和MAX(updated_at)对比两边最新记录
真正可控的零丢失方案:pg2mysql + 逻辑复制补丁
这不是开箱即用的流程,但能解决核心矛盾:让 MySQL 在迁移中持续追上 PG 的新写入。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
前提:PostgreSQL 版本 ≥ 10,且已启用 wal_level = logical,并创建了复制槽(replication slot)。
- 用
pg2mysql完成初始全量迁移(加--no-truncate,保留旧数据) - 启动一个轻量级逻辑解码消费者(如
wal2json插件 + 自定义 Go 脚本),把新增/更新的行转成 MySQL 的INSERT ON DUPLICATE KEY UPDATE语句 - 将该脚本输出直接 pipe 给
mysql -u user -p db - 当增量延迟
性能影响:逻辑复制会增加约 8–12% 的 CPU 开销;wal2json 输出需过滤大字段(如 text 类型),否则网络传输可能成为瓶颈。
最容易被忽略的细节:text 类型截断与字符集漂移
PostgreSQL 的 text 字段在 MySQL 中映射为 TEXT(65535 字节上限),但实际迁移时往往被悄悄截断,且不报错。
更隐蔽的问题是字符集:PG 默认 UTF8,MySQL 若用 utf8mb3(非 utf8mb4),emoji 和部分生僻字会变成 ? 或乱码。
必须检查:
- 源表中
LENGTH(column::text) > 65535的行数:SELECT COUNT(*) FROM table WHERE LENGTH(content::text) > 65535; - MySQL 目标库是否已设
CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci -
pg2mysql配置中未提供字段长度重映射选项,需提前在目标库建表时改用MEDIUMTEXT或LONGTEXT

















