PG 的 EXPLAIN ANALYZE 是什么
PostgreSQL 的 EXPLAIN 加上 ANALYZE 会真正执行语句,给出每个节点的实际行数、耗时与循环次数;再加 BUFFERS 会输出共享缓存命中与磁盘读取的块数。这三个选项组合起来,就能判断慢在计算、慢在 IO,还是估算偏差导致选错了连接方式。
基本信息
| 基本用法 | EXPLAIN (ANALYZE, BUFFERS) SELECT … |
|---|---|
| TIMING | 默认开启逐节点计时,设为 off 可减少测量开销 |
| actual time | 首行到末行的实测耗时,单位毫秒 |
| rows 与 loops | 每次循环的平均行数,总行数等于 rows 乘 loops |
| BUFFERS | shared hit 是内存命中,read 是从磁盘读的块数 |
| 写语句实测 | 放进事务执行后 ROLLBACK |
实测输出示例
实测输出示例
EXPLAIN (ANALYZE, BUFFERS, TIMING)
SELECT o.id, o.total
FROM orders o
WHERE o.user_id = 100;
-- 输出示例:
-- Index Scan using idx_orders_user on orders o
-- (actual time=0.05..0.30 rows=12 loops=1)
-- Index Cond: (user_id = 100)
-- Buffers: shared hit=5 read=2
-- Planning Time: 0.3 ms
-- Execution Time: 0.5 ms写语句安全实测
写语句安全实测
BEGIN;
EXPLAIN (ANALYZE) UPDATE orders SET status = 'x' WHERE id = 1;
ROLLBACK; -- 实测完立刻回滚,避免真的改了数据
-- 只关心计划形态时,用不带 ANALYZE 的 EXPLAIN 即可,不会执行语句
EXPLAIN UPDATE orders SET status = 'x' WHERE id = 1;关键字段读法
| 字段 | 含义 | 怎么用 |
|---|---|---|
| actual time | 首行..末行耗时(毫秒) | 找出耗时占比最高的节点 |
| rows 与 loops | 每次循环平均行数 | 总读取量要乘 loops |
| Buffers: shared hit | 命中共享内存的块数 | 命中高说明数据基本在缓存里 |
| Buffers: read | 从磁盘读取的块数 | 持续大量 read 说明缓存不足 |
| Planning / Execution Time | 计划耗时与执行耗时 | 判断计划本身是否也偏慢 |
典型使用场景
- 确认索引是否被使用,或者退化成了顺序扫描
- 判断慢在 IO 还是慢在计算:结合 Buffers 与 actual time
- 排查连接方式:嵌套循环、哈希连接、归并连接哪个被选中
- 验证统计信息准确性:对比估算行数与实际行数
- 上线前用真实数据量验证执行计划
- 评估写语句的计划:事务内执行后回滚
TIMING off 会关闭逐节点计时,只保留汇总的 Planning Time 与 Execution Time:节点多、调用频繁时能明显减少测量开销,适合只看整体耗时而不需要定位到具体节点的时候。
ANALYZE 会真正执行语句:写操作必须在事务里执行后回滚,并避开业务高峰;重查询同样消耗真实资源,先在预发库或从库上验证。