# 正确使用 EXPLAIN

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

---

`EXPLAIN` 是观测工具，也会改变观测成本。普通 EXPLAIN 只规划；加 ANALYZE 后真实执行；加 timing、buffers、WAL 后又增加不同程度的采集工作。先明确问题，再选择选项。

## 7.2.1 `EXPLAIN`、`ANALYZE`、`BUFFERS`、`WAL` {#item-7-2-1}

推荐的机器证据：

```sql
EXPLAIN (
  ANALYZE,
  BUFFERS,
  WAL,
  SETTINGS,
  SUMMARY,
  FORMAT JSON
)
SELECT ...;
```

各选项回答：

- `ANALYZE`：真实 rows、loops、time，且真的执行；
- `BUFFERS`：shared/local/temp hit/read/dirtied/written；
- `WAL`：records、FPI、bytes，主要对写路径有意义；
- `SETTINGS`：影响 planner 且偏离 built-in default 的设置；
- `SUMMARY`：planning/execution summary；
- JSON/YAML/XML：给程序解析，文本留给人读。

buffer hit 不是“没有 I/O”，只表示 page 已在 PostgreSQL shared buffers；它可能刚由另一 backend 或操作系统读入。单次 warm run 不能代表 cold cache。WAL bytes 也不等于磁盘最终写入 bytes，FPI、compression、并发与 checkpoint 都会影响。

若只验证估算与树形，可先 `EXPLAIN (FORMAT JSON)`，避免执行高风险/高成本 SQL；若要 actual，先用生产等价的只读副本、L1 或受控参数范围。不要在事故高峰对未知查询直接加 ANALYZE。

## 7.2.2 规划时间、执行时间与客户端时间 {#item-7-2-2}

EXPLAIN 的 Planning Time 与 Execution Time 都是服务器视角，通常不包含：

- 连接建立、pool queue；
- 客户端序列化/反序列化；
- 网络传输与 result consumption；
- application thread/event-loop 排队；
- transaction 中前后其他 SQL；
- 在开始采集前已经发生的重试。

而 planner cost 连服务器毫秒也不是。诊断至少对齐四个时间：

```text
application span
  = pool/connect + server round trip + decode + application work

server statement duration
  = parse/plan（可能缓存）+ lock/wait + executor + output

EXPLAIN planning/execution
  = 本次受 instrument 影响的服务器测量

dashboard sample
  = 采样时间窗中的聚合/近似
```

`TIMING off` 仍保留 actual rows/loops 与总 execution time，可降低逐节点读时钟开销；当目标是 cardinality 而非每节点时间时更合适。反复执行要记录次数、warmup、参数和并发，报告分布而不是最佳一次。

## 7.2.3 对写语句使用 `ANALYZE` 的事务保护 {#item-7-2-3}

`EXPLAIN ANALYZE UPDATE/DELETE/INSERT/MERGE` 会真实改数据、触发 trigger、约束、WAL 与锁。最小演练模式：

```sql
BEGIN;
SET LOCAL statement_timeout = '30s';
SET LOCAL lock_timeout = '5s';

EXPLAIN (ANALYZE, BUFFERS, WAL, SETTINGS, FORMAT JSON)
UPDATE ...;

ROLLBACK;
```

rollback 能恢复同一 PostgreSQL transaction 内的数据变化，却不能撤销 sequence 值、某些外部副作用、通知接收方已经看到的消息，或 volatile function 对外部系统的动作。trigger/function 在演练环境也要审查。DDL、`VACUUM` 与不能在 transaction block 运行的命令又有不同边界。

生产写计划优先从同分布 L1、脱敏 clone 或 read-only EXPLAIN 开始；确需在线 ANALYZE 时限定精确 key、窗口、owner、timeout、before/after fingerprint，并确认复制/WAL预算。不要用 `ROLLBACK` 三个字把 R2/R3 动作伪装成 R0。

本章所有 ANALYZE 都是专属 fixture 上的 SELECT。task 保存原始 JSON，再由 Python 读取语义字段；它不 grep 文本节点，也不固定动态 cost/time。若 JSON 无效或 actual 行数漂移，分析立即失败。

---

[上一节：优化器如何选择路径](../01/) · [返回本章目录](../) · [下一节：统计信息与估算偏差](../03/) ·
[查看全书目录](/toc/) · [查看索引中心](/indexes/)
