perf(db): 收入口径回填改为分批脚本

迁移 104 里对 order_items 的全表 UPDATE 实测 34.4 秒(375,447 行),
远超默认语句超时 15s,单事务迁移会拖住启动甚至直接失败。

- 104 只保留 DDL 与索引/约束,删除全表 UPDATE;
- 新增 scripts/backfill-revenue-basis.ts:按 id 分批、幂等、支持
  --dry-run / --batch-size / --max-batches(kebab 与 camel 两种写法);
- package.json 增加 revenue:backfill;
- migrate.ts 启动时做一次带索引计数,仍有 unknown 时打印告警并给出命令,
  不阻塞启动;
- 文档补充回填步骤与「不执行的后果」。

验证:
- 实测 37.5 万行全表更新 34.4s → 脚本按批执行,单批 5000 行;
- 功能验证:单条订单项置 unknown → 脚本回填 → 金额与 basis 恢复正确;
- 启动告警验证:保留 1 条 unknown 重启 → 日志出现告警;回填后计数归零;
- 全新库从 102 迁移到 107 仍成功(2s)。
This commit is contained in:
yml2213
2026-10-25 12:02:26 +08:00
parent f10fefc303
commit ad1e1bc884
5 changed files with 256 additions and 29 deletions
+17
View File
@@ -430,6 +430,23 @@ DELETE FROM schema_migrations WHERE name ~ '^(10[3-9]|11[0-2])_';
旧的逐列改造脚本 `scripts/rewrite-local-db-2026-10-23.sql` 已随迁移合并作废,移入 [archive/2026-10-23/](archive/2026-10-23/);只在追溯当时 `carrier_type → cost_model` / `fulfillment_mode` 的改造矩阵时查阅,**不要在新环境执行**。
### 8.1 收入口径回填(迁移 104 不做全表更新)
`order_items.revenue_amount_fen` / `revenue_basis` 在迁移 `104` 里**只建列,不刷历史数据**:
375,447 行的全表 `UPDATE` 实测约 **34 秒**,超过默认语句超时(`DATABASE_STATEMENT_TIMEOUT_MS=15s`),
放进单事务迁移会拖住启动甚至直接失败。
历史行由脚本分批回填(幂等、可续跑):
```bash
npm run revenue:backfill -- --dry-run # 统计待回填量并抽样预览
npm run revenue:backfill # 默认每批 5000 行
npm run revenue:backfill -- --batch-size=2000 --max-batches=100
```
服务启动时会做一次带索引的计数:若仍有 `revenue_basis='unknown'` 的订单项,会打印告警并提示执行上面的命令。
**不执行回填的后果是销售事实收入偏低**(订单项收入按 0 计),不会报错,所以部署后必须确认该计数为 0。
`check-sql-guard.ts` 改为以 `main` 为基线校验迁移字节:**已发布的迁移不可修改**,未合并分支上的新迁移仍可重写;基线可用 `MIGRATION_BASELINE_REF` 覆盖,找不到基线时跳过该项检查。
---