Seq Scan 成本 = startup_cost + (pages × seq_page_cost) + (rows × cpu_tuple_cost),基于统计信息和配置参数估算,不访问真实数据。

Seq Scan 的成本是怎么算出来的
PostgreSQL 估算 Seq Scan 成本时,核心是「读多少页 + 处理多少行」。它不查真实数据,只依赖统计信息(pg_class.relpages 和 pg_class.reltuples)和配置参数。
基础公式近似为:startup_cost + (pages × seq_page_cost) + (rows × cpu_tuple_cost)。其中:
-
startup_cost通常为 0(除非带LIMIT或排序) -
seq_page_cost默认是 1.0,可调;代表随机读一页的开销相对值 -
cpu_tuple_cost默认是 0.01,反映每行 CPU 处理开销 - 页数来自
relpages,但若 WHERE 条件有选择率(selectivity),会按比例缩减扫描页数(注意:不是简单乘,还涉及缓冲区命中率估算)
Index Scan 成本为什么经常比 Seq Scan 高
看起来走索引更快,但优化器算得更细——Index Scan 成本 = 索引页访问成本 + 回表(heap fetch)成本。尤其当条件选择率不高、或索引列区分度低时,它很容易输。
关键点:
- 索引扫描页数由
index_pages × selectivity估算,但 B-tree 深度也参与计算(深度越大,越倾向放弃) - 回表成本占大头:每匹配一个索引项,就要去主表读一页(或几页)取完整行,这部分用
random_page_cost(默认 4.0)计价,远高于seq_page_cost - 如果查询需要返回大量行(比如
WHERE status IN ('a','b','c')匹配 30% 行),优化器常判断「不如全扫一遍」,直接选Seq Scan
如何让 Index Scan 成本变低(让优化器愿意用)
不是建了索引就自动变快,得让成本模型「信服」索引更优。常见有效操作:
- 确保统计信息最新:
ANALYZE table_name;(否则reltuples错误会导致选择率误判) - 调低
random_page_cost(SSD 场景可设为 1.1–1.5),缩小回表惩罚 - 用覆盖索引避免回表:
CREATE INDEX ON t (a) INCLUDE (b, c);,此时成本中去掉 heap fetch 项 - 限制结果集:
LIMIT 10会让Index Scan的 startup_cost 显著降低(优化器知道不用扫完)
看执行计划时容易忽略的两个细节
成本数字本身是相对值,单位无意义,但差 2 倍以上通常代表路径差异显著。真正要盯的是:
-
Rows Removed by Filter:如果这个值巨大(比如扫描 100 万行,只留 10 行),说明谓词不适合走索引,或者索引没覆盖过滤条件 - 实际耗时与成本严重偏离时(如
Index Scan成本低但执行慢),大概率是缓存未预热(首次运行)、或work_mem不足导致排序/聚合落盘,和成本模型无关










