From b58513c48d93aaf60a971d5c8ff1fc9b7075c1a8 Mon Sep 17 00:00:00 2001 From: wecom-fullstack Date: Mon, 5 Oct 2026 13:02:02 +0800 Subject: [PATCH] =?UTF-8?q?docs(ddl):=20runbook=20=E9=A6=96=E6=AD=A5?= =?UTF-8?q?=E5=BC=BA=E5=88=B6=E3=80=8C=E8=BF=81=E7=A7=BB=E5=89=8D=E5=83=8F?= =?UTF-8?q?=20dump=20=E5=93=88=E5=B8=8C=E3=80=8D(--apply=20=E4=B9=8B?= =?UTF-8?q?=E5=89=8D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CMA-DDL-RUNBOOK-20261005 / parent: CMA-KPI-20261003-D-T1 - docs/db-migration-runbook.md 新增 §3.0:任何 --apply 之前对每张受影响表落 全表有序 (PK, 受影响列) dump,记录 sha256 + 行数 + 字节数,归档 backups/pre-ddl-/ - 含可直接复制的一行命令(ORDER BY 主键保证字节级确定性) - §4 发布 checklist 第 4 条(列级 ALTER)指向 §3.0 仅文档;零生产库/零部署/零重启。 --- docs/db-migration-runbook.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/db-migration-runbook.md b/docs/db-migration-runbook.md index 5b99d4f9..74ed2e46 100644 --- a/docs/db-migration-runbook.md +++ b/docs/db-migration-runbook.md @@ -30,6 +30,27 @@ ## 3. 迁移步用法(`backend/scripts/db_migrate.py`) +### 3.0 强制前置步 —— 任何 `--apply` **之前**:迁移前像 dump 哈希 + +> 来源:`CMA-KPI-20261003-D-T1` 只读回读复核(2026-10-05)。落地前两侧(设计 10:11 / 执行 10:38)**只留了行数/计数基线**, +> 未留全表 `(PK, 受影响列)` 有序 dump 哈希 ⇒ **迁移前像不可得**,事后只能用「四时点基线谓词对拍 + 值域指纹 + 时间戳 + +> `MODIFY` 类型保持」四路**替代取证**。本步是事后自证「**存量取值零改写**」的**唯一直接依据**,不可省、不可推迟到 `--apply` 之后。 + +对本任务**每一张受影响表**,在 `--apply` **之前**落一次全表有序 `(PK, 受影响列)` dump,记录 `sha256 + 行数 + 字节数`; +产物归档 `backups/pre-ddl-/`(与 `backups/pre-ddl-entity-dim-20260923/` 同约定),随任务件留痕。 + +可直接复制(把 `DB / TBL / COLS` 换成任务值;`COLS` **首位必须是主键**): + +```bash +DB=cma TBL=treasury_limits COLS='id,status,limit_amount' D="backups/pre-ddl-$(date +%Y%m%d-%H%M%S)" sh -c 'mkdir -p "$D"; mysql -N -B --default-character-set=utf8mb4 "$DB" -e "SELECT $COLS FROM $TBL ORDER BY ${COLS%%,*}" > "$D/$TBL.before.tsv"; sha256sum "$D/$TBL.before.tsv"; wc -lc < "$D/$TBL.before.tsv"' +``` + +- `ORDER BY ${COLS%%,*}`(即主键)保证字节级确定性:同一份数据两跑,`sha256` 必须一致。 +- 行数与 `SELECT COUNT(*)` 对账:`wc -l` 即行数(`-N` 无表头;末行缺换行符时 ±1 属正常)。 +- 多表:每张受影响表各跑一次,逐表记录「表名 + sha256 + 行数 + 字节数」。 +- 现成实现可复用 ops 探针 `wecom-ops/scripts/probe_cma_kpi_t1_readback_20261005.py --check`(自动落 `02b-current-id-tv.json` 全量行值基线)。 +- 本步只用**只读**语句(`SELECT` + `sha256sum`),零生产写;`--apply` 与回滚命令见下。 + ```bash cd /root/cma-management/backend ./venv/bin/python3 scripts/db_migrate.py --check # 只读预检(默认动作) @@ -53,7 +74,8 @@ cd /root/cma-management/backend 2. 本地 `--check` 应能列出该表缺失(证明 ORM 已注册)。 3. 提交推送 → 部署链 `[4b]` 用特权账号建表 → 重启 → 冒烟 `schema_check` 通过。 4. 若模型**改列**(新增/改名/改类型):`create_all` 不处理 → 必须写独立迁移脚本/`ALTER`(参考 - `backend/scripts/migrate_ext_input_ledgers_20260915.py`、`treasury_migrate.py` 的 `up()/down()` 模式)。 + `backend/scripts/migrate_ext_input_ledgers_20260915.py`、`treasury_migrate.py` 的 `up()/down()` 模式); + **执行任何 `ALTER` 前先走 §3.0 迁移前像(全表有序 dump 哈希)**。 5. **不要**让运行库账号重新获得 CREATE 来「绕过」:那正是事故根因。 ## 5. `cma_api` 的 CREATE 授权回收(项目Bot 执行)