# 先分类再抢救

LLMS 索引： [llms.txt](/llms.txt)

---

“corruption”不是一个恢复方案。至少要区分：存储的字节/页是否错误、从源数据派生的
结构是否错误、业务意义是否错误。检测工具、恢复来源和可接受损失都不同。

## 35.2.1 物理页、存储与 checksum 错误 {#item-35-2-1}

### 物理异常的证据链

典型入口：

```text
checksum mismatch
invalid page / invalid page header
could not read/write block
short read
I/O error / filesystem remount read-only
storage medium error / controller reset
unexpected relation segment size or missing file
```

这些信号仍需定位：

```text
one block / one relation / one tablespace / one device / many hosts
heap / index / toast / catalog / WAL / control
primary only / replica too / backup copy too
read-time detection / write-time failure / recovery-time failure
```

checksum failure 说明“读出的 data page 与页内 checksum 不一致”，不自动说明是磁盘：
坏内存、DMA/controller、虚拟化、filesystem、软件 bug 或离线篡改都可能改变字节。

### 交叉副本不能只比较 SQL 行

在相同 system identifier/lineage 下，可比较：

```text
same relation identity and logical object
same or corresponding block/LSN context
primary, replica, backup and storage snapshot
kernel/storage errors on each host
```

物理 replica 可能从 primary 接收已经损坏的逻辑变化，也可能各自发生局部介质损坏；
共享存储/镜像又可能让“多个副本都有同样错误”并不独立。恢复源要有独立故障域与实际
校验，不是名字叫 replica 就可信。

### 默认路线

```text
preserve corrupt original
verify hardware/storage path
identify last known-good source
restore/reseed a new working copy
validate physical + logical + business state
```

只有在没有健康来源且明确接受损失时，才考虑 best-effort extraction。

## 35.2.2 索引、排序规则与派生结构错误 {#item-35-2-2}

### 派生结构可以重建，但先证明 source

index、materialized view、search vector、rollup 与 cache 都由别的状态生成。典型信号：

```text
amcheck raises B-tree invariant error
same predicate gives seqscan/indexscan different rows
unique index behavior conflicts with expected equality
collation stored version differs from provider actual version
OS/ICU upgrade changes comparison rules
primary and standby use different provider versions
```

先关闭 planner 路径做诊断时，只在 clone 或有界 read-only 查询里进行：

```sql
BEGIN READ ONLY;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_indexonlyscan = off;
SET LOCAL enable_bitmapscan = off;
-- bounded invariant query
ROLLBACK;
```

这只能帮助比较，不是修复，也不能保证 seqscan 本身绕过 heap 损坏。

### collation 是外部语义依赖

collation object 把 SQL 名称映射到 libc 或 ICU provider。text B-tree 的顺序依赖比较
规则；provider 升级后，旧 index 中 tuple 的物理顺序可能不再满足新比较规则。仅更新
`collversion` 会消除 mismatch 提示，却不会重新排列已有 index。

因此安全顺序是：

```text
inventory affected collation dependencies
  -> verify on clone
      -> REINDEX affected indexes/materialized structures
          -> validate
              -> REFRESH VERSION metadata
```

数据库级 default collation 还会影响更多对象；要从 catalogs 枚举依赖，不能只重建
报错的第一条 index。

### 派生异常也可能来自 heap

`heapallindexed` 发现 heap tuple 没有对应 index tuple 时，原因可能是 index 本身，也
可能是 heap/visibility/transaction state 异常。REINDEX 后 `amcheck` 通过只是一个信号；
还要验证 heap、toast、constraints 和业务 invariants。

## 35.2.3 逻辑不变量、应用写错与语义损坏 {#item-35-2-3}

### checksum 全绿也可能数据完全错误

```text
UPDATE accounts SET balance = 0;
wrong tenant predicate
duplicate external event applied twice
currency unit conversion error
missing ledger entry
referential rule enforced only in application
out-of-order CDC correction
```

PostgreSQL 会把这些合法写入按 WAL、checksum 和 replication 正确保存。物理工具不会
知道“余额不应为负”或“订单总额应等于明细”。

业务不变量应提前定义：

```sql
-- 结构约束能表达的尽量进入数据库
ALTER TABLE account
ADD CONSTRAINT balance_domain CHECK (balance >= 0);
```

跨行、跨表、跨系统不变量需要 reconciliation：

```text
row count by partition/tenant
sum/count/min/max with known semantic
ledger debit = credit
event id uniqueness and sequence
source-system vs database token
snapshot + change-log continuity
```

MD5/SHA digest 适合证明同一有序投影是否相同，不证明投影本身业务正确；必须绑定 SQL、
排序、NULL/encoding 与 snapshot time。

### 恢复路线

- 错误发生时间明确且需整体回退：PITR 到隔离实例，再做差异恢复；
- 有审计/事件/ledger：按稳定业务 ID 重放或补偿；
- 上游系统为事实源：重新同步并核对删除/版本；
- 局部错误且可逆：受控 correction transaction；
- 外部副作用已经发生：数据库恢复之外做业务补偿。

不要在原实例上反复 PITR。第 32 章的恢复目标、timeline 与 replay 验证仍适用。

## 35.2.4 三类问题的恢复来源不同 {#item-35-2-4}

### 决策矩阵

| 已证明的异常 | 首选 source | 典型动作 | 核心验收 |
|---|---|---|---|
| heap data page | verified backup/replica/snapshot | restore/reseed new copy | checksum + rows + business |
| index only | verified heap | REINDEX exact dependency | amcheck + query equivalence |
| collation drift | heap + intended provider/version | reindex then refresh | dependency + order + invariants |
| materialized/derived | authoritative base tables/events | rebuild/refresh | source-to-derived reconciliation |
| app wrong write | PITR/audit/event/upstream | recover/diff/compensate | business invariants |
| multiple/unknown | immutable evidence + expert analysis | stop and escalate | missing facts resolved |

### 分类置信度

不要把一个工具的结果写成绝对结论：

```yaml
classification: physical-page
confidence: high
supports:
  - data_checksums=on
  - offline pg_checksums bad=1
  - scan raises XX001 on exact heap
contradicts:
  - none observed
not_proven:
  - root hardware component
  - other pages are clean
  - backups are independent and usable
```

`pg_checksums` 找到 1 个坏 checksum，不等于整个集群只有 1 处问题：可能还有未覆盖对象、
业务语义损坏或未来才读出的设备错误。反过来全绿也只覆盖被扫描的 data pages。

### 停止线

以下任一出现，路线转 `STOP_AND_ESCALATE`：

1. system identifier、timeline 或 binary/PGDATA 归属不明；
2. 原始 evidence 已被多次写入，动作时间线无法复原；
3. checksum、amcheck、业务结果相互矛盾；
4. 所有已知 backup/replica 可能共享故障；
5. 唯一副本无法安全克隆；
6. 需要 `zero_damaged_pages`、`ignore_invalid_pages` 或 `pg_resetwal` 才能继续；
7. 数据损失范围涉及监管、财务、隐私或安全事件。

---

[上一节：现场保护与操作边界](../01/) · [返回本章目录](../) · [下一节：页与 checksum 证据](../03/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
