actual time 明显大于 cost 说明执行计划中某节点的 cost 低估了真实开销,最常见原因是磁盘 i/o 或内存不足导致临时文件落盘,源于统计信息偏差或配置参数与实际硬件不匹配。

actual time 明显大于 cost,说明什么
这通常不是配置或语法问题,而是执行计划里某个节点的 cost 低估了真实开销——最常见的是磁盘 I/O 或内存不足导致的临时文件落盘。PostgreSQL 的 cost 模型基于统计信息和默认参数(比如 random_page_cost、effective_cache_size),一旦实际硬件性能或数据分布偏离假设,估算就会失真。
-
actual time是实测耗时(毫秒),cost是规划器内部抽象单位,二者无直接换算关系 - 若某节点
actual time是cost的 10 倍以上,优先怀疑该节点触发了磁盘排序(Sort Method: external merge)或哈希表溢出(Hash Table Size: XkB (overflows: Y)) - 检查
EXPLAIN ANALYZE输出中是否含Buffers:行;若shared read=数值大,说明大量物理读,cost却按缓存命中估算,自然偏低
如何快速定位 cost 严重失准的节点
别从头扫输出,直接找三个信号:外部操作标记、缓冲区读写异常、行数预估崩坏。PostgreSQL 9.6+ 的 EXPLAIN ANALYZE 会把关键偏差点“标亮”。
- 搜索
external:如Sort Method: external merge或Hash Chain: external,这类节点的cost完全没考虑磁盘延迟 - 看
Buffers:下的shared read=是否远大于shared hit=;若读多写少且actual time高,说明缓存失效,但 planner 仍按effective_cache_size高估了命中率 - 对比每个节点的
Rows Removed by Filter:和Actual Rows:;若过滤掉 99% 行但Plan Rows:还是原始量级,说明统计信息过期,cost基于错误基数计算
调整哪些参数能让 cost 更贴近 actual time
不能盲目调参,得对应具体偏差类型。重点改两个参数,其余保持默认更安全。
- 若出现大量
external操作:调低work_mem上限(比如从 4MB 改为 2MB),让 planner 更早预判内存不够,主动选更保守但估算准确的计划(如用 nested loop 替代 hash join) - 若
shared read高但cost低:调高random_page_cost(SSD 可设为 1.1–1.5,HDD 用 3–4),让 planner 更重视随机 I/O 代价 - 避免碰
seq_page_cost和cpu_tuple_cost:除非你刚换了 CPU 或存储架构,否则它们对偏差影响小,乱调反而让其他查询变差
为什么 analyze table 不总能修复 cost 偏差
ANALYZE 只更新列值分布和行数统计,但 planner 的 cost 模型还依赖全局配置和运行时资源状态。很多偏差根源不在数据本身。
- 统计信息新鲜 ≠ 执行环境匹配:比如
work_mem被会话级覆盖、effective_cache_size设为 1GB 但机器实际有 32GB 内存,planner 仍按 1GB 算缓存效率 - 分区表或继承表容易漏分析:只
ANALYZE parent_table不会递归更新子分区,需显式ANALYZE每个子表或启用autovacuum_analyze_scale_factor - 函数内联或表达式索引会让 planner 无法准确估算中间结果行数,此时
ANALYZE无能为力,得靠SET enable_hashjoin = off这类临时禁用策略验证
actual time 波动极大,但 cost 几乎不变——这时候问题大概率不在 planner,而在系统级资源争抢(如其他进程占满 I/O 或 memory pressure 导致 page cache 被清空)。










