七月 22, 2026
摘要:在本教程中,您将学习到 PostgreSQL 内部统计信息工作原理与优化指南。
目录
核心观点
查询计划器(Query Planner)在制定 SQL 执行计划时,并不会直接扫描原始数据表,而是高度依赖数据库的统计信息。这些核心统计信息存放在 pg_statistic 系统表中,而 pg_stats 是为其提供的高可读性视图。(注:在 PostgreSQL 的命名规范中,复数形式的通常是视图,单数形式的通常是表)。
pg_stats 关键统计指标解析

当你执行 ANALYZE 命令后,系统会扫描表数据并生成以下关键统计信息:
-
n_distinct(唯一值数量):衡量列中不重复值的数量。如果是主键(每行均唯一),该值在数据库中会特殊显示为-1。 -
null_frac(空值比例):代表该列中 Null 值所占的百分比。 -
correlation(相关性):表示数据在磁盘上物理分布的有序程度,数值介于 -1 到 1 之间。- 接近 0:代表数据物理分布非常随机,计划器会倾向于选择 顺序扫描 (Sequential Scan) 以避免高昂的随机读取代价。
- 接近 -1 或 1:代表数据物理分布高度有序,计划器会更倾向于选择 索引扫描 (Index Scan)。
-
most_common_values(MCV) 与most_common_freqs:记录列中最常出现的值及其对应的百分比频率。这能帮助计划器准确预判数据倾斜情况。
代价计算与扫描方式对比(索引扫描 vs. 顺序扫描)

查询计划器会基于“代价 (Cost)”这一数学模型来决定使用哪种扫描方式,其中包含三个核心代价指标:
random_page_cost:从磁盘中随机拉取一个数据页的代价(索引扫描常用)。seq_page_cost:顺序读取连续数据页的代价(顺序扫描常用)。cpu_tuple_cost:CPU 处理单行数据(Tuple)的代价。
💡 观点对比:为什么有时查询带索引,却依然触发全表顺序扫描? 如果查询条件匹配的数据量极大(如占总行数的 20%),通过索引在百万行数据中进行上万次“随机页面抓取”所消耗的 CPU 周期和时间,会远超直接从头到尾遍历整张表。因此,计划器会判定顺序扫描成本更低。相反,当查询条件命中极少行数(如偏冷门数据)时,计划器才会果断选择索引扫描。
统计信息的进阶调整策略
默认的统计信息可能无法反映复杂的数据分布,此时可通过以下两种方案进行进阶调整:
1. 直方图 (Histograms) 精度调整
- 适用场景:时间段、数值区间等范围查询。
- 问题所在:PostgreSQL 默认只收集 100 个数据桶 (Buckets),在查询精细的范围数据时容易出现统计偏差。
- 解决方法:使用
ALTER TABLE ... ALTER COLUMN ... SET STATISTICS 1000将某一列的统计精度提升至 1000 甚至更高。 - 注意:精度调高会导致
ANALYZE耗时变长,建议仅针对具体列调整,切勿进行全局修改。

2. 扩展统计信息 (Extended Statistics)
- 适用场景:处理多列强相关的联合查询(例如:
city = 'Cheyenne'ANDstate = 'Wyoming')。 - 问题所在:计划器默认将多列条件视为独立事件并把概率相乘,从而严重低估返回行数。
- 解决方法:使用
CREATE STATISTICS命令来显式声明列之间的依赖关系,帮助计划器获得准确的关联预估。

慢查询排查 6 步法清单
当发现数据库查询缓慢且行为不符合预期时,可按照以下 6 步进行排查:
- 对比预估与实际行数:运行
EXPLAIN ANALYZE命令,从执行计划最深层的节点(Deepest node)开始排查,找出“预估行数”与“实际行数”偏差严重的地方。 - 检查
pg_stats现状:检查偏差列的n_distinct、高频值数组和直方图,确认它们是否符合你对实际业务数据的了解。 - 手动触发
ANALYZE:特别是在大批量数据导入或迁移后,系统自动清理机制(auto-vacuum)可能尚未介入,此时必须手动执行ANALYZE以更新过期的统计信息。 - 提高统计精度:如果分析后预估依然不准,尝试将该列的统计目标值(Statistics Target)提高至 1000 甚至 10000。
- 建立关联统计:如果偏差节点涉及两列或以上的过滤条件,请评估其相关性,并为其创建扩展统计信息(Extended Statistics)。
- 重写查询逻辑:如果穷尽上述手段后查询依然低效,请考虑重写 SQL 语句或从其他业务维度寻找性能提升的方法。

结论
“查询计划器的聪明程度,完全取决于你喂给它的统计信息。”
开发者务必确保统计信息准确并维持在合理的范围内,定期执行分析(Analyze),这是优化 PostgreSQL 查询性能最根本且有效的基础。
参考
pg_stats: How Postgres Internal Stats Work