MySQL2PG 工具产生的背景
在实际迁移场景里,把 MySQL、PostgreSQL 做异构转换与同步,经常会踩到这些坑:
- 无法全自动把 MySQL 的 DDL 转成 PostgreSQL。转换过程中还会遇到大量语法不兼容问题,最终仍要手工修修补补,耗时耗力。
- 工具无法自动化完成全量表同步,往往需要手动选择单表/批量表、配置字段映射;同步进度也缺乏可视化,很难评估整体耗时。
- 无法自动同步 MySQL 的数据库用户信息:哪些用户要迁移、每个用户的密码是多少;尤其密码遗忘时,人工核对会消耗大量时间。
- 无法自动同步用户权限,难以做到精细化授权控制,操作风险高。
- 尤其是 MySQL 上的 FUNCTION 很难自动迁移。几百个 FUNCTION 如果靠手动转换,人力成本会非常高。
围绕这些问题,先对工具所需模块与功能做了系统梳理,并形成手稿第一版设计。
MySQL2PG 功能模块设计手稿
最终实现的模块与功能流程如下(按执行顺序):
开始
│
├─▶ [Step 0] test_only 模式?
│ ├─ 是 → 测试 MySQL & PostgreSQL 连接 → 显示版本 → 退出
│ └─ 否 → 继续
│
├─▶ [Step 1] 转换表结构 (tableddl: true)
│ ├─ 读取 MySQL 表定义
│ ├─ 字段类型智能映射(如 tinyint(1) → BOOLEAN)
│ ├─ lowercase_columns 控制字段名大小写
│ └─ 在 PostgreSQL 中创建表(skip_existing_tables 控制是否跳过)
│
├─▶ [Step 2] 同步数据 (data: true)
│ ├─ 若 use_table_list=true → 仅同步 table_list 中的表
│ ├─ 若 truncate_before_sync=true → 清空目标表
│ ├─ 分批读取 MySQL 数据(max_rows_per_batch)
│ ├─ 批量插入 PostgreSQL(batch_insert_size)
│ └─ 并发线程数由 concurrency 控制
│
├─▶ [Step 3] 转换索引 (indexes: true)
│ ├─ 主键、唯一索引、普通索引 → 自动重建
│ └─ 批量处理(max_indexes_per_batch=20)
│
├─▶ [Step 4] 转换函数 (functions: true) ←【V1.0 未完全实现】
│ └─ 支持函数映射(如 NOW() → CURRENT_TIMESTAMP)
│
├─▶ [Step 5] 转换用户 (users: true)
│ └─ MySQL 用户 → PostgreSQL 角色(带密码)
│
├─▶ [Step 6] 转换表权限 (table_privileges: true)
│ └─ GRANT SELECT ON table → GRANT USAGE, SELECT
│
└─▶ [Final Step] 数据校验 (validate_data: true)
├─ 查询 MySQL 和 PostgreSQL 表行数
├─ 若 truncate_before_sync=true 且不一致 → 报错中断
└─ 若 truncate_before_sync=false → 记录不一致表,继续执行
└─ 最终输出「数据量校验不一致的表统计」表格
源代码仓库: https://github.com/xfg0218/MySQL2PG
编程工具选择
项目从 0 到 1 开发前,调研了国内主流 AI IDE 工具,包括 Trae、CodeBuddy、通义灵码,优劣势对比如下。
| 功能维度 |
Trae |
CodeBuddy |
通义灵码 |
| AI 核心模式 |
支持 Builder 和 Builder MCP 的模式 |
Craft 智能体、双模型驱动 |
支持智能代码补全、智能校验代码质量、测试 CASE 生成 |
| 代码生成能力 |
支持从 0-1 项目的生成 |
支持不同的语言 |
支持代码的优化、代码提示、代码续写 |
| 多模态支持 |
支持 go/java/Python/C++ |
支持流程的编排、智能体的协作 |
编程智能体、工程级变更 |
| 生态集成 |
支持 VS Code 插件 |
支持微信生态、腾讯云服务等 |
阿里云生态、可对接钉钉 |
由于该项目需要从 0 开始,并且选用 Go 语言开发,开发过程中更依赖“理解上下文 + 自动编排代码 + 生成测试步骤”的能力,因此最终选择 Trae 作为开发工具。
参考资料:
trae: https://www.trae.cn/
codebuddy: https://www.codebuddy.ai/
通义灵码: https://lingma.aliyun.com/
为什么会选择 golang?主要考虑到 Golang 可直接编译为机器码,具备运行效率快、跨平台、内存占用率少、启动快、可二进制部署等特点。
工具整体功能效果
使用的软件版本
本次测试使用 MySQL 与 PostgreSQL 单机版,版本信息如下:
-- go 的版本
$ go version
go version go1.24.2 darwin/amd64
-- mysql的版本
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.44 |
+-----------+
1 row in set (0.00 sec)
-- PG的版本
postgres=# select version();
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 16.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
(1 row)
使用的数据集
- MySQL 数据库中包含不同字段类型、不同存储引擎、不同字符编码、涉及关键字、主外键、自增列等,共 1339 张表用于自动转换。
- 1339 张表共有 1768 个索引,包含主键索引、单字段索引、复合索引等。
- 数据库内存在 5 个不同用户:有的用户仅有 SELECT 权限、有的仅有 DELETE 权限、有的仅有 UPDATE 权限,有的用户对几十张表具有全部操作权限。
- 实际测试转换对象数量汇总如下:
+--------------------------+----------------+
| 阶段 | 对象数量 |
+--------------------------+----------------+
| 转换表结构 | 1339 |
| 同步表数据 | 1339 |
| 转换表索引 | 1768 |
| 转换库用户 | 5 |
| 转换表权限 | 15 |
+--------------------------+----------------+
仅测试连接部分
在 config.yml 中提供测试连接参数 test_only。当该参数开启时,仅测试数据库连接,其余步骤不执行;连接测试完成后输出版本信息并退出。
当 mysql.test_only = true 时,仅测试连接 MySQL,日志如下:
+-------------------------------------------------------------+
1. MySQL连接测试完成,版本信息已显示,退出程序。
+-------------------------------------------------------------+
| 数据库版本信息: |
+--------------+----------------------------------------------+
| 数据库类型 | 版本信息 |
+--------------+----------------------------------------------+
| MySQL | 5.7.44 |
| PostgreSQL | PostgreSQL 16.1 on x86_64-pc-linux-gn... |
+--------------+----------------------------------------------+
当 postgresql.test_only = true 时,仅测试连接 PostgreSQL,日志如下:
+-------------------------------------------------------------+
2. PostgreSQL 连接测试完成,版本信息已显示,退出程序。
+-------------------------------------------------------------+
| 数据库版本信息: |
+--------------+----------------------------------------------+
| 数据库类型 | 版本信息 |
+--------------+----------------------------------------------+
| MySQL | 5.7.44 |
| PostgreSQL | PostgreSQL 16.1 on x86_64-pc-linux-gn... |
+--------------+----------------------------------------------+
全流程运行结果
在 config.yml 的 conversion 模块中分别开启 tableddl/data/indexes/users/table_privileges/validate_data 后,工具会按顺序依次执行,并在完成后汇总各阶段对象数量与耗时。
示例日志如下(截取):
1. 开始转换表结构...
进度: 3.45% (1/29) : 表 acl_space 已存在,跳过创建
进度: 6.90% (2/29) : 表 users_20251201 已存在,跳过创建
进度: 10.34% (3/29) : 表 act_id_group 已存在,跳过创建
进度: 13.79% (4/29) : 表 user 已存在,跳过创建
2. 同步表数据...
进度: 17.24% (5/29) : 同步表 acl_space 数据成功,共有 0 行数据,数据校验一致
进度: 17.24% (6/29) : 同步表 users_20251201 [--------------------] 100.00%
进度: 20.69% (6/29) : 同步表 users_20251201 数据成功,共有 1 行数据,数据校验一致
进度: 24.14% (7/29) : 同步表 act_id_group 数据成功,共有 0 行数据,数据校验一致
进度: 27.59% (8/29) : 同步表 user 数据成功,共有 0 行数据,数据校验一致
3. 转换表索引...
进度: 31.03% (9/29) : 转换索引 idx_user_id 成功
5. 开始转换用户...
进度: 34.48% (10/29) : 转换用户 mysql2pg@% 的权限成功
进度: 37.93% (11/29) : 转换用户 user1@% 的权限成功
进度: 41.38% (12/29) : 转换用户 user2@% 的权限成功
进度: 44.83% (13/29) : 转换用户 user1@localhost 的权限成功
进度: 48.28% (14/29) : 转换用户 user2@localhost 的权限成功
6. 转换表权限...
进度: 51.72% (15/29) : 转换表权限成功
进度: 58.62% (17/29) : 转换表权限成功
进度: 68.97% (20/29) : 转换表权限成功
进度: 72.41% (21/29) : 转换表权限成功
进度: 82.76% (24/29) : 转换表权限成功
进度: 93.10% (27/29) : 转换表权限成功
进度: 95.30% (28/29) : 转换表权限成功
进度: 100.00% (29/29) : 转换表权限成功
----------------------------------------------------------------------
各阶段及耗时汇总如下:
+--------------------------+----------------+-----------------------+
| 阶段 | 对象数量 | 耗时(秒) |
+--------------------------+----------------+-----------------------+
| 转换表结构 | 4 | 0.84 |
| 同步表数据 | 4 | 1.69 |
| 转换表索引 | 1 | 0.05 |
| 转换库用户 | 5 | 0.24 |
| 转换表权限 | 15 | 1.41 |
+--------------------------+----------------+-----------------------+
| 总耗时 | | 4.23 |
+--------------------------+----------------+-----------------------+
按照指定表进行同步
当在 config.yml 的 conversion 模块中把 use_table_list 设置为 true 时,工具会仅同步 table_list 中的表,适合只迁移关注表的场景;完成后同样会汇总耗时。
2. 同步表数据...
进度: 50.00% (1/2) : 同步表 user 数据成功,共有 0 行数据,数据校验一致
进度: 50.00% (2/2) : 同步表 users_20251201 [--------------------] 100.00%
进度: 100.00% (2/2) : 同步表 users_20251201 数据成功,共有 1 行数据,数据校验一致
----------------------------------------------------------------------
各阶段及耗时汇总如下:
+--------------------------+----------------+-----------------------+
| 阶段 | 对象数量 | 耗时(秒) |
+--------------------------+----------------+-----------------------+
| 同步表数据 | 2 | 0.91 |
+--------------------------+----------------+-----------------------+
| 总耗时 | | 0.91 |
+--------------------------+----------------+-----------------------+
同步过程中会显示百分比进度,便于随时掌握数据同步状态。
指定同步表进度展示
数据同步不一致时的提示
当把 truncate_before_sync 设置为 false 时,可能出现数据重复或不一致。同步期间控制台日志会提示 数据校验不一致,并在完成后输出 数据量校验不一致的表统计,方便定位问题。
2. 同步表数据...
进度: 50.00% (1/2) : 同步表 user 数据成功,共有 0 行数据,数据校验一致
进度: 50.00% (2/2) : 同步表 users_20251201 [--------------------] 100.00%
进度: 100.00% (2/2) : 同步表 users_20251201 数据成功,共有 1 行数据,数据校验不一致
+------------------+----------------+------------------+
数据量校验不一致的表统计:
+------------------+----------------+------------------+
| 表名 | MySQL数据量 | PostgreSQL数据量 |
+------------------+----------------+------------------+
| users_20251201 | 1 | 2 |
+------------------+----------------+------------------+
----------------------------------------------------------------------
各阶段及耗时汇总如下:
+--------------------------+----------------+-----------------------+
| 阶段 | 对象数量 | 耗时(秒) |
+--------------------------+----------------+-----------------------+
| 同步表数据 | 2 | 0.66 |
+--------------------------+----------------+-----------------------+
| 总耗时 | | 0.66 |
+--------------------------+----------------+-----------------------+
仅转换用户及表权限时的提示
当在 config.yml 的 conversion 模块中只开启 users 和 table_privileges 时,工具会自动转换用户与表权限,全程无需手动干预,并在结束后汇总转换对象与耗时。
5. 开始转换用户...
进度: 5.00% (1/20) : 转换用户 mysql2pg@% 的权限成功
进度: 10.00% (2/20) : 转换用户 user1@% 的权限成功
进度: 15.00% (3/20) : 转换用户 user2@% 的权限成功
进度: 20.00% (4/20) : 转换用户 user1@localhost 的权限成功
进度: 25.00% (5/20) : 转换用户 user2@localhost 的权限成功
6. 转换表权限...
进度: 30.00% (6/20) : 转换表权限成功
进度: 40.00% (8/20) : 转换表权限成功
进度: 55.00% (11/20) : 转换表权限成功
进度: 60.00% (12/20) : 转换表权限成功
进度: 75.00% (15/20) : 转换表权限成功
进度: 90.00% (18/20) : 转换表权限成功
----------------------------------------------------------------------
各阶段及耗时汇总如下:
+--------------------------+----------------+-----------------------+
| 阶段 | 对象数量 | 耗时(秒) |
+--------------------------+----------------+-----------------------+
| 转换库用户 | 5 | 0.24 |
| 转换表权限 | 15 | 1.35 |
+--------------------------+----------------+-----------------------+
| 总耗时 | | 1.59 |
+--------------------------+----------------+-----------------------+
错误日志分析及执行日志查看
错误日志
MySQL2PG 运行时会默认在当前路径生成 errors.log,用于记录运行过程中的错误信息。排查失败原因时,优先从这里入手更高效。
[2025-12-29 13:09:54] ERROR: 插入表 users_20251201 数据失败: 批量插入失败: ERROR: duplicate key value violates unique constraint "users_20251201_pkey" (SQLSTATE 23505), 数据样本: [[49] [50] [51]]
执行日志查看
MySQL2PG 运行时也会默认在当前路径生成 conversion.log,用于记录详细转换过程。如果某一步出现异常,可结合该日志快速定位问题(例如表不存在、权限跳过等)。
*****
[2025-12-29 14:14:17] 进度: 89.66% (26/29)
[2025-12-29 14:14:17] 表 users 在PostgreSQL中不存在,跳过权限授予
[2025-12-29 14:14:17] 进度: 93.10% (27/29)
[2025-12-29 14:14:17] 表 products 在PostgreSQL中不存在,跳过权限授予
[2025-12-29 14:14:17] 进度: 96.55% (28/29)
[2025-12-29 14:14:17] 表 orders 在PostgreSQL中不存在,跳过权限授予
[2025-12-29 14:14:17] 进度: 100.00% (29/29)
如果你平时也在做迁移/同步的稳定性建设,把转换与运行日志纳入日常巡检流程会更稳;相关实践也经常会落到 运维/DevOps/SRE 的范畴里。
MySQL2PG 工具后续计划
- 支持 MySQL 的 FUNCTION 自动转换为 PostgreSQL 函数。
- 根据日志级别,在日志中增加转换后的 PostgreSQL DDL 语句。
- 继续优化数据同步效率,提升吞吐与总体耗时表现。
- 增加 MySQL 不同版本到 PostgreSQL 不同版本的转换测试覆盖。
- 转换表权限时,增加对用户权限明细的提示。
- 增加日志级别(如 INFO、DEBUG、ERROR 等),避免重复生成
conversion.log 与 errors.log,并让日志更易检索与定位。
推荐阅读与讨论:你可以在 云栈社区 继续交流 MySQL/PostgreSQL 迁移与工具落地的细节问题。