结构同步需先用skeema或pg-comparator扫描差异生成最小化变更脚本,人工前置确认外键、函数等兼容性,禁用索引再重建以提升导入性能,分块哈希校验数据一致性。
结构同步不能只靠 mysqldump 或 pg_dump
直接用导出工具做全量 ddl 同步,在千万级以上表或含上百张表的库中,大概率会卡在约束依赖、权限缺失、字符集不一致、序列/自增起点错位这些地方。比如 pg_dump --schema-only 导出后在新集群执行,可能因 create extension 顺序不对而报 type "hstore" does not exist;mysql 下 mysqldump --no-data 生成的建表语句若含 algorithm=instant,在旧版本目标库上直接报错。
- 先用工具扫描差异:推荐
skeema(MySQL)或pg-comparator(PostgreSQL),它们能比对 schema 并生成最小化变更脚本,而非整库重建 - 人工干预点必须前置:外键、全文索引、函数/存储过程、用户自定义类型——这些没法自动映射,得提前列清单逐个确认兼容性
- 注意默认值陷阱:如 MySQL 的
TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP在严格模式下迁到 PostgreSQL 会失败,需转为DEFAULT NOW()并加USING转换逻辑
增量迁移时,binlog 和 wal 日志解析是性能分水岭
真正卡住大数据迁移的,往往不是全量同步,而是增量追平阶段——日志解析慢、apply 延迟高、断点续传不可靠。比如用 canal 解析 MySQL binlog,若未关闭 table filter 或未调优 batchSize,单线程消费 10 万 TPS 的写入时延迟可达小时级;PostgreSQL 的 logical replication 若源端有大量 UPDATE 且无主键,会退化为全表扫描式同步,I/O 直接打满。
- MySQL 场景优先启用
ROW格式 +binlog_row_image=FULL,避免 UPDATE 时丢失旧值导致目标端无法比对 - PostgreSQL 务必为同步表显式添加主键(即使业务不用),否则
pgoutput协议无法定位变更行,降级为 snapshot 模式 - 别迷信“零代码”工具:金仓
KDTS或 AWSDMS在异构迁移时虽支持语法自动转换,但遇到 Oracle 的NUMBER(38)→ PostgreSQL 的NUMERIC映射,仍需手动校验精度截断风险
索引不是越多越好,迁移期要主动降配再重建
很多团队在目标库建完表就立刻建全套索引,结果全量加载阶段插入速度从 5 万行/秒掉到 300 行/秒,还触发磁盘爆满。本质是 B+ 树索引在大批量 INSERT 时频繁分裂和排序,远超数据写入本身开销。实测显示:禁用索引后导入 10 亿行耗时 2.1 小时,再建索引耗时 3.8 小时;而边插边建索引总耗时超 14 小时,且中途失败无法 resume。
- MySQL:导入前执行
SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET SQL_LOG_BIN=0;,加载完再开启 - PostgreSQL:用
CREATE TABLE ... WITH (fillfactor=100)预留空间,导入后执行VACUUM FULL再建索引 - 关键原则:唯一约束可保留,普通二级索引一律延迟创建;复合索引优先建高频查询覆盖的前缀字段,而非照搬源库
验证环节最容易被跳过,但 CHECKSUM 和抽样 ORDER BY RAND() 都不靠谱
用 SELECT CRC32(GROUP_CONCAT(...)) 对全表算校验和?当表里有 TEXT 字段含换行或 NULL,不同数据库排序规则一变结果就不同。用 ORDER BY RAND() LIMIT 1000 抽样?在 10 亿行表上执行一次 RAND() 排序,IO 和 CPU 开销堪比全表扫描。
- 真正可行的是分块哈希:按主键范围切片(如
id BETWEEN 1 AND 1000000),每块算MD5(GROUP_CONCAT(CONCAT_WS('|', col1, col2, ...))),再比对各块摘要 - 业务关键字段必须单独核对:比如订单表的
amount总和、状态分布比例,用聚合 SQL 直接比数字,比逐行校验快两个数量级 - 别信“迁移工具自带校验”:AWS DMS 的 validation 功能默认只比行数,不校验内容;
pt-table-checksum在大表上会锁表,得配合--chunk-size和--sleep手动控速











