7.3 统计信息与估算偏差
planner 不逐行检查数据再选计划;那相当于先执行查询。它读取 relation size、单列统计和可选扩展统计,近似选择率。理解近似来源,才能判断该 ANALYZE、提高 target、建扩展统计,还是改条件表达。
7.3.1 直方图、高频值、空值率与相关性
pg_stats 是对 pg_statistic 的可读视图,常用字段:
| 字段 | 含义 |
|---|---|
null_frac | NULL 比例 |
n_distinct | 正值为估计 distinct 数;负值表示与行数比例 |
most_common_vals/freqs | 高频值与频率 |
histogram_bounds | 排除 MCV 后近似等频桶边界 |
correlation | 列逻辑顺序与物理行序的相关程度 |
MCV 适合倾斜 equality;histogram 估 range;correlation 影响 ordered index scan 的 heap page 成本预期。它们是 ANALYZE sample 的摘要,不是约束或精确 count。statistics target 提高会扩大 sample/MCV/histogram 细节,同时增加 ANALYZE、planning 与 catalog 成本。
本章 tenant_id 中 1 占 90%,应成为 MCV;cold tenant 各 10 行。custom plan 看见具体参数时可用 MCV,估出 90000/10。generic plan不知道 $1,只能使用平均选择率,约估 100。
7.3.2 扩展统计解决跨列相关
单列统计分别知道:
region='east' ≈ 25%
order_status='paid' ≈ 25%若假设独立,AND 约为 6.25%,即 6250 行;fixture 实际把 east 完全对应 paid,所以是 25000。反之 east+cancelled 实际为 0,单列仍估约 6250。
扩展统计类型解决不同问题:
dependencies:列之间近似函数依赖,修正组合条件;ndistinct:列组合 distinct 数,帮助 GROUP BY 等;mcv:记录常见值组合,能表达常见或不可能组合;- expression statistics:为表达式本身收集统计。
实验执行:
CREATE STATISTICS shop_private.ch07_region_status_stats
(dependencies, mcv)
ON region, order_status
FROM shop_private.ch07_plan_probe;
ALTER STATISTICS shop_private.ch07_region_status_stats
SET STATISTICS 1000;
ANALYZE shop_private.ch07_plan_probe;CREATE STATISTICS 只定义对象,ANALYZE 才填数据。修复后 present estimate 为 25000,impossible estimate 降到 planner 的非零下限 1。不能据此说扩展统计“证明 east 绝不会 cancelled”;约束负责拒绝,统计只服务估算,而且数据变化后会过期。
7.3.3 数据倾斜、陈旧统计与采样误差
估算偏差按顺序排查:
- query parameter/类型/cast 是否与生产一致;
last_analyze、修改量与分布是否变化;- MCV/histogram 是否能容纳关键倾斜;
- 多列是否相关却被独立估计;
- 条件是否包裹列、使用 expression/函数而无统计;
- join/partition parent 是否缺统计;
- sample randomness 是否让边界值波动;
- planner 是否因 generic plan 看不到参数。
只运行 ANALYZE 而不对比 estimate/actual,不能证明问题已修。提高全库 default_statistics_target 也通常太粗;先对问题 column/statistics object 局部提高,再衡量 planning/catalog 成本。
本章每次 setup 后普通 ANALYZE 的相关组合估算在约 6250 周围小幅变化,这是随机采样的预期;analyzer 断言修复前误差至少 2 倍、修复后不超过 1.5 倍,而不固定 6250。稳定测试检查关系,动态证据保存具体值。
统计正确也不保证计划最快:cost parameters、cache、并发、I/O 与 executor 能力仍参与。它只让 planner 对“会有多少行”拥有更好输入。
上一节:正确使用 EXPLAIN · 返回本章目录 · 下一节:分区裁剪的两种时机 · 查看全书目录 · 查看索引中心