设计细化二 · 有测试了

类型怎么落、存量怎么读、动手前看见什么

类型映射字典(15 个用例已跑)· 全量分块与一致性起点 · plan 的输出与确认规则

类型映射:先立规矩,再填表

  1. 绝不静默降级:`lossy` 以上必须在 plan 里列出来,用户确认才继续。
  2. 字典优先、探测兜底:字典没覆盖 → 目标库建影子列试写一行,成了就采纳,不成就拒绝该列。
  3. 列级可覆盖:`job.yaml` 能强制指定目标类型,人的判断优先于字典。
  4. 拒绝的是列,不是任务:单列映射不了,其余列照常同步。
4 档无损 / lossy / 需确认 / 不支持
60+ 条双向映射规则
15 个表驱动测试,已进 CI
1 个真代码文件:typemap.go

三个最容易翻车的映射

MySQL tinyint(1) → boolean生态里当布尔用,但 2..127 会溢出。所以标「需确认」,不能当 smallint 悄悄放过去。
utf8mb4 行宽 65535 字节宽表多列 varchar 直接建表失败 → 预检按列宽估算,超限建议长列改 text,并在 plan 里标出。
timestamptz → datetime(6)时区被丢掉。默认统一按 UTC 存,读取方必须知道 —— 这不是"技术上能过"就能算无损。

其余按字典:金额永远走 decimal(不许 float 糊过去)、jsonb→json 丢键序、bigint unsigned→numeric(20,0)、数组落地 JSON 需确认。

存量读取:按主键形态选策略

主键形态策略断点粒度
单列整型min/max 均分区间块
复合主键首列切区间 + 块内 keyset 游标块
文本 / UUIDkeyset 游标(pk > last ORDER BY pk LIMIT n)块
无主键(PG)按 ctid 区间块
无主键(MySQL)只能单连接顺序扫(隐藏 rowid 不可用)表(失败整表重来)
这一条要在预检里说清楚:MySQL 无主键表既不能块级续跑,也不支持 upsert 增量 —— 目标端只能 insert-only + 全量校验。
另外极稀疏主键(1 和 10¹²)区间切分会退化成大量空块 → 先采样取边界再切。

一致性起点:两个库的解法不一样

PostgreSQL 10+复制协议建书签时 EXPORT_SNAPSHOT → 每个分块连接 SET TRANSACTION SNAPSHOT,所有块看到同一时刻
MySQL毫秒级 FLUSH TABLES WITH READ LOCK 取位点 → START TRANSACTION WITH CONSISTENT SNAPSHOT → 解锁
云上禁锁时先起快照再取位点 + lookback 回看窗口 + upsert 幂等去重;如实标注极小重复可能
接缝快照期间书签不推进(防变更流水被清);切换条件=快照读完 且 增量追到快照起点之后

并发默认 4 连接(上限 16),每连接 QPS 上限 200,块间可 sleep;plan 把「内存 ≈ 并发 × 块行数 × 行宽」算给用户看。

`plan`:动手之前先看见全部后果

预检 3 项需要注意
  [auto] PG-02 max_replication_slots 余量 0 → 改为 12(ALTER SYSTEM + reload)
         undo: ALTER SYSTEM SET max_replication_slots = 10;
  [dba ] PG-01 wal_level = replica,需要 logical(要重启实例)
         影响:连接中断 10–30 秒;WAL 增长约 10–20%
  [info] PG-07 本版本无 slot 磁盘阀 → 改用「落后 5 GB 暂停并告警」

范围  12 张表,估算 8.4 M 行 / 2.1 GB(orders 占 71%)
将执行 4 个动作(写库,需确认)· 预计初始化 6–9 分钟,之后 p99 约 40 ms
情况行为
全是 ok / auto问一次「执行以上 4 个动作?」
有需确认(类型/代价)逐条列出差异,必须显式 --accept
有 blocked退出码 3 + 定制教程,没有忽略开关
CI 环境--json + 退出码,绝不弹交互

这一轮的产出