7.2 正确使用 EXPLAIN
EXPLAIN 是观测工具,也会改变观测成本。普通 EXPLAIN 只规划;加 ANALYZE 后真实执行;加 timing、buffers、WAL 后又增加不同程度的采集工作。先明确问题,再选择选项。
7.2.1 EXPLAIN、ANALYZE、BUFFERS、WAL
推荐的机器证据:
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 规划时间、执行时间与客户端时间
EXPLAIN 的 Planning Time 与 Execution Time 都是服务器视角,通常不包含:
- 连接建立、pool queue;
- 客户端序列化/反序列化;
- 网络传输与 result consumption;
- application thread/event-loop 排队;
- transaction 中前后其他 SQL;
- 在开始采集前已经发生的重试。
而 planner cost 连服务器毫秒也不是。诊断至少对齐四个时间:
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 的事务保护
EXPLAIN ANALYZE UPDATE/DELETE/INSERT/MERGE 会真实改数据、触发 trigger、约束、WAL 与锁。最小演练模式:
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 行数漂移,分析立即失败。
上一节:优化器如何选择路径 · 返回本章目录 · 下一节:统计信息与估算偏差 · 查看全书目录 · 查看索引中心