# 实战：解释订单查询的计划变化

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

---

综合实验不追求把某个 node 调成最快，而是建立一条可审计推理链：确定性数据制造已知分布，保存修复前 JSON 计划，只改变一个统计/条件因素，再保存修复后计划并由程序检查关系。

## 7.7.1 用固定数据种子制造估算偏差 {#item-7-7-1}

确认 service 指向可写 `pg36_shop` L1：

```bash
export PGSERVICEFILE=/absolute/private/path/pg_service.conf
export PGSERVICE=pg36-admin
cd static/labs/ch07
export PG36_EVIDENCE_DIR="$PWD/evidence/ch07/all-$(date -u +%Y%m%dT%H%M%SZ)"

./task.sh all
```

`all` 的顺序：

```text
ch04-v1 verify-before
  → marker collision guard + deterministic setup
  → correlated plans before
  → CREATE STATISTICS + ANALYZE
  → correlated plans after
  → custom/generic parameter plans
  → constant/wrapped/generic partition plans
  → parent ANALYZE
  → Python semantic assertions
  → fixture verify + ch04-v1 verify-after
```

fixture 分布固定：

```text
rows=100000
east+paid=25000
east+cancelled=0
tenant 1=90000
tenant 1001=10
```

`region/status` 分别四等分但完全对应。普通单列统计近似把两个 25% predicate 相乘，所以两种组合都估约 6250。具体值随 ANALYZE sample 波动，不能 hard-code；raw `stats-before-*.json` 保存本次 estimate、actual、buffers、settings 和时间。

参数实验选择 128-byte payload，确保 hot tenant 的 heap fetch 与 cold tenant 有明显路径取舍。analyzer 不强制节点必须是 Seq/Index，只强制 custom estimate 接近实际、generic 对两个参数使用同一 estimate，且 hot generic 偏差至少 100 倍。

## 7.7.2 修复统计与条件表达后重新比较 {#item-7-7-2}

扩展统计只改变 planner knowledge，不改变数据、index 或 SQL：

```text
present:    ~6300 → 25000 / actual 25000
impossible: ~6300 → 1     / actual 0
```

这证明问题属于跨列相关，不需要先建组合 index；若查询性能仍不达标，再用第 9 章方法评估 index。扩展统计改善 estimate 也可能不改变 node，因为本查询没有 region/status index 且需要 seq scan；“plan shape 没变”不代表修复无效。

分区实验只改变 predicate：

```text
occurred_on = constant          → one child at plan time
date_trunc(... occurred_on ...) → four children, child filters
generic $1 equality             → one executed child, 3 removed
```

修复 wrapped 条件应在应用边界先算月初/月末，再直接写 partition-key 半开范围。创建 expression index 可能帮助分区内 filter，却不保证 partition bounds 能由该表达式裁剪；index 与 pruning 是两种机制。

父表统计单独验证 0→4。若只看 child autoanalyze，会遗漏 parent。生产维护频率由分布变化而非固定日历决定，并观察 `pg_stat_progress_analyze`、锁与资源。

查看结果：

```bash
cat "$PG36_EVIDENCE_DIR/plan-summary-all.txt"
python3 -m json.tool "$PG36_EVIDENCE_DIR/plan-summary-all.json"
```

一次实测：

```text
status=ok
correlated_estimate=6352->25000/actual=25000
impossible_estimate=6275->1/actual=0
custom_hot=Seq Scan/estimate=90000/actual=90000
custom_cold=Index Scan/estimate=10/actual=10
generic_estimate=100/hot_actual=90000/cold_actual=10
partition_counts=constant:1,wrapped:4,generic:1
partition_parent_stats=0->4
```

时间与 buffers 用来比较同一次受控实验，不进入稳定 summary。要比较性能，应重复运行并记录 cache/并发条件；本章只验 cardinality 与裁剪机制。

### 安全复位

实验对象保留供观察。确认不再需要后：

```bash
export PG36_RESET_TOKEN=RESET_CH07_PLAN_LAB
export PG36_RESET_TARGET=pg36_shop/shop_private/ch07
export PG36_EVIDENCE_DIR="$PWD/evidence/ch07/reset-$(date -u +%Y%m%dT%H%M%SZ)"
./task.sh reset
```

reset 先复核 database、primary、ch04-v1、两个 relation marker 与两个 token，再只删除 ch07 relation。错误 token 必须 exit 3，且对象仍存在；成功后 `remaining_ch07_relations=0`，ch04-v1 relation checksum 仍为：

```text
f8a7bfae59c6d16cd323abecfefe1014
```

## 7.7.3 把一条有证据的计划规则追加到规约 {#item-7-7-3}

v0.1 的 `PREF-PLAN-005` 已声明：

```text
看到 Seq Scan、Nested Loop 或高 cost 不直接判错；
先定位 estimate/actual、loops、buffers、wait 与 workload，
再用可回退对照验证 statistics、SQL 或 index 变更。
```

[`baseline-v0.2-proposal.json`](/labs/ch07/baseline-v0.2-proposal.json) 不改写不可变 v0.1，而是基于其 canonical checksum 提案：

```text
base=0.1.0
candidate=0.2.0
rule=PREF-PLAN-005
statement_change=none
change=evidence-and-runtime-check
```

新增 runtime check：

```text
保存机器可读 plan，比较 estimate/actual、参数计划与裁剪范围；
不得以节点名或 cost 单独判定回归。
```

Python analyzer 会重新计算 v0.1 canonical checksum，拒绝 proposal 绑定到被悄悄修改的 base；也验证三项 evidence artifact 存在。当前 proposal 仍是 candidate，因为 promotion 还要求：

1. PostgreSQL 14–18 兼容矩阵通过；
2. 至少一个不同硬件或规模复测；
3. 合并为独立、不可变的 v0.2 release artifact。

这体现规则证据的正确节奏：单次 PostgreSQL 18.6 实验足以形成候选 runtime check，不足以宣称跨版本普遍阈值。后续复测即使 node type 不同，只要 cardinality 与 partition pruning 的因果关系仍成立，规则就得到进一步确认；若机制变化，就修正 scope/compatibility，而不是让测试强行 grep 旧节点。

完成本章后，读者应提交的不是一张漂亮计划图，而是：

```text
manifest + source hashes
raw plans before/after
machine summary
fixture distribution
PostgreSQL/session facts
business model verify-before/after
rule proposal + known promotion gap
```

下一章会从 Pigsty 的真实慢查询时间窗选择 query family，再沿本章方法进入单条计划。

---

[上一节：建立计划证据基线](../06/) · [返回本章目录](../) · [下一章：抽丝剥茧：慢 SQL 诊断方法论](/slow-query-diagnosis/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
