# 第 10 章 WAL 与 Checkpoint - 配套代码

本章脚本带你「亲眼看见」WAL 在写：从一次 INSERT 之后 LSN 跳了多少字节，到 fsync 开关对吞吐的影响，到一次 CHECKPOINT 实际刷了几个 buffer。

## 准备工作

1. 本章脚本会自己 `CREATE TABLE ch10_xxx`，**不需要手动跑 init.sql**。
2. 安装依赖：`pip install "psycopg[binary]>=3.1"`。
3. （可选）通过环境变量覆盖默认连接：`export PG_DSN="host=... port=... dbname=... user=..."`。
4. 部分脚本用到 `CHECKPOINT;` 和 `pg_stat_bgwriter`，需要 superuser 权限（默认用 `postgres` 跑就行）。

## 脚本一览（推荐运行顺序）

| 脚本 | 一句话说明 | 关键 PG 特性 |
|------|------------|--------------|
| `01_lsn_walk.py` | 看每次 INSERT 之后 LSN 怎么递增、平均每行多少字节 WAL | `pg_current_wal_lsn` / `pg_wal_lsn_diff` / `pg_walfile_name` |
| `02_synchronous_commit.py` | 对比 `synchronous_commit = on / off / local` 的吞吐 | 异步提交 / WAL Writer |
| `03_checkpoint_observe.py` | 写 5 万行制造脏页 → 手动 CHECKPOINT → 看 `pg_stat_bgwriter` 增量 | checkpoint 触发条件 / `buffers_checkpoint` |
| `04_wal_size_estimate.py` | 量 INSERT/UPDATE/DELETE/TRUNCATE 各产生多少 WAL，对比 `wal_compression` | FPI / `wal_compression` |

运行示例：

```bash
python 01_lsn_walk.py
python 02_synchronous_commit.py
python 03_checkpoint_observe.py
python 04_wal_size_estimate.py
```

## 预期输出

`01_lsn_walk.py` 会打印每次 INSERT 之后 LSN 的字节增量，类似：

```
op                             lsn               +bytes
------------------------------------------------------------
INSERT row-1                   0/16E7A310               64
INSERT row-2                   0/16E7A350               64
...
总写入 WAL   = 78912 字节  ≈ 77.1 KB
平均每行     ≈ 78.9 字节
```

`02_synchronous_commit.py` 会显示 `off` 模式相对 `on` 的提速倍数（云盘上常见 5～10x）。

## 常见报错

- `connection refused` → PG 未启动，检查 `pg_isready -h 127.0.0.1`
- `permission denied to execute function pg_current_wal_lsn` → 用 superuser 运行；或 `GRANT EXECUTE ON FUNCTION pg_current_wal_lsn() TO appuser;`
- `permission denied to execute CHECKPOINT` → CHECKPOINT 仅 superuser 可执行
- `cannot execute CHECKPOINT during recovery` → 你连到了备库，请连主库
- `wal_compression` 显示为空 → PG 14 之前只支持 on/off，PG 15+ 才支持 lz4/zstd
