postgresql的explain中cost是优化器基于i/o和cpu的相对开销估算值,非实际时间;actual time才是真实毫秒耗时,含启动与总时间、行数及循环次数。

EXPLAIN 输出里 cost 是什么,为什么它不等于执行时间
PostgreSQL 的 EXPLAIN 中的 cost 是优化器估算的相对开销值,不是毫秒,也不是 CPU 时间。它基于磁盘 I/O(1.0 = 一次顺序页读取)和 CPU 操作(0.01 = 一次简单运算)建模,所有数值都按比例缩放,只用于比较不同执行计划的优劣。
- 实际执行时,
cost完全不反映并发、缓存命中率、磁盘延迟或网络传输——比如一个cost=1000的索引扫描,若数据全在 shared_buffers 里,可能比cost=200的磁盘排序快得多 -
enable_seqscan=off强制走索引,可能让cost翻倍但实际更快;反之,random_page_cost设太高会让优化器回避真实高效的随机读 - 如果
EXPLAIN ANALYZE显示actual time远高于cost对应的“理论值”,大概率是统计信息过期(ANALYZE没跑)或work_mem不足导致落盘
EXPLAIN ANALYZE 的 actual time 字段怎么读,各阶段含义是什么
actual time 是真实耗时(单位毫秒),格式为 actual time=0.025..124.852 rows=1234 loops=1:前面是启动时间(从开始到返回第一行),后面是总时间(从开始到最后一行返回),rows 是该节点实际输出行数,loops 表示该节点被重复执行次数(常见于嵌套循环内层)。
- 注意
loops > 1时,actual time是单次耗时,不是总耗时;总耗时 ≈ (启动时间 + 总时间) ×loops,但 PostgreSQL 不直接给出,得自己算 - 如果某节点
actual time很大但rows很小,可能是 I/O 等待(如Buffer read高)、锁等待(Lock wait出现在日志里),或函数调用(如pg_sleep())卡住 -
Planning Time和Execution Time在EXPLAIN ANALYZE结尾单独列出,前者高说明查询结构复杂或统计信息混乱,后者才是执行本身耗时
哪些 cost / actual time 差异说明优化方向明确
当 cost 和 actual time 出现系统性偏差,往往指向可落地的调优动作,而不是玄学猜测。
-
Seq Scan的actual time远低于cost→ 数据基本在内存,但优化器还按磁盘读估算,检查effective_cache_size是否设得太低 -
Hash Join节点actual time极高且Hash table size超出work_mem→ 必须调大work_mem或改写为Merge Join(需有序) -
Index Scan行数远少于rows估算值(比如估算 10000,实际 12),但actual time却很高 → 可能索引字段选择性差,或存在隐式类型转换(如WHERE text_col = 123),触发全索引扫描
EXPLAIN ANALYZE 在生产环境怎么安全用,避免拖垮系统
EXPLAIN ANALYZE 会真实执行查询,对写操作、大表扫描、锁竞争场景有风险。不能直接在高峰期对 UPDATE 或 SELECT FOR UPDATE 跑。
- 读查询加
LIMIT 10再EXPLAIN ANALYZE—— 但注意:加LIMIT可能改变执行计划(比如跳过排序),此时应配合OFFSET 0或用pg_hint_plan固定计划再测 - 想看执行过程但不想等完,用
EXPLAIN (ANALYZE, TIMING OFF, SUMMARY OFF)关闭详细计时和汇总,减少开销 - 对疑似慢查询,先
EXPLAIN(不带 ANALYZE)看计划是否合理;只有计划没问题但实际慢,才上EXPLAIN ANALYZE;如果计划就错(比如该走索引却走全表),优先查统计信息和条件写法
最常被忽略的是:cost 模型依赖的参数(random_page_cost、cpu_tuple_cost 等)和真实硬件脱节时,优化器永远“算不对”。调参不是玄学,但得从 EXPLAIN ANALYZE 里找证据——比如 SSD 服务器还用默认 random_page_cost=4.0,那 cost 就天然高估随机读 4 倍。










