PostgreSQL 扩展统计信息是什么?为什么多列相关性会影响执行计划?
简化版
扩展统计信息用于帮助 PostgreSQL 理解多列之间的相关性、组合基数和函数依赖。普通统计通常按单列估算,如果两列强相关,优化器可能严重估错行数,进而选错 join 顺序或索引。
详细版
例如 country='CN' 和 city='Beijing' 强相关。优化器如果把两个条件当独立事件,可能把结果估得过小或过大。
PostgreSQL 可以用:
CREATE STATISTICS st_user_country_city
ON country, city
FROM users;
ANALYZE users;
扩展统计能收集 ndistinct、dependencies、mcv 等信息,帮助优化器更准确估算。它不是加速结构,本身不存数据访问路径,仍要配合索引和 ANALYZE。
完整版教学
一、优化器为什么要估算行数
数据库执行 SQL 前要选计划:走哪个索引、先 join 哪张表、用 nested loop 还是 hash join。这些选择都依赖“估计会返回多少行”。
如果估算错了,计划就可能错。原本只返回 100 行的查询被估成 100 万行,优化器可能放弃索引;反过来,实际 100 万行被估成 100 行,也可能选择糟糕的 nested loop。
统计信息就是优化器的眼睛。
二、单列统计为什么不够
普通统计主要记录每列的分布,例如最常见值、直方图、不同值数量。但它默认列之间近似独立。
现实数据常常不独立。province='广东' 和 city='广州' 强相关;is_deleted=false 和 deleted_at IS NULL 也高度相关。
如果两个条件各自选择率都是 10%,独立假设会估成 1%。但真实相关时结果可能仍接近 10%,误差 10 倍。
三、扩展统计怎么创建
可以为多列创建统计对象:
CREATE STATISTICS st_orders_status_pay
ON status, pay_status
FROM orders;
ANALYZE orders;
创建统计对象后必须 ANALYZE,否则优化器没有新统计数据可用。统计对象只影响估算,不等于索引。
四、常见统计类型怎么理解
| 类型 | 作用 | 适合场景 |
|---|---|---|
ndistinct | 估算组合不同值数量 | 多列 GROUP BY |
dependencies | 识别函数依赖 | 邮编决定城市 |
mcv | 多列最常见组合 | 状态组合分布倾斜 |
例如订单状态和支付状态组合里,FINISHED + PAID 可能占 80%,FINISHED + UNPAID 几乎不可能。多列 MCV 能让优化器知道这种组合分布。
五、扩展统计和索引的关系
扩展统计不提供访问路径,所以它不能替代索引。它只是帮助优化器更准确判断某个路径划不划算。
索引:告诉数据库怎么找
统计:告诉优化器大概会找到多少
一个查询可能同时需要扩展统计和组合索引。统计让计划选得对,索引让执行跑得快。
六、常见误区与追问
- 误区:扩展统计建完查询就一定更快。 它只改善估算,是否更快取决于计划是否因此变好。
- 误区:扩展统计可以替代联合索引。 统计不是访问路径,不能直接减少扫描。
- 误区:创建统计后不用维护。 数据分布变化后需要
ANALYZE更新统计。 - 追问:多列相关性会导致什么问题? 行数估算偏差,进而选错 join 顺序、join 算法或索引。
- 追问:怎么判断估算错? 看
EXPLAIN ANALYZE里 estimated rows 和 actual rows 的差距。
七、加强记忆
记忆钩子:索引是路,统计是地图;多列相关性像地图上没画山路,路线规划就容易估错时间。
回答这题时把“优化器估算、独立假设、多列相关、CREATE STATISTICS、不能替代索引”串起来。它是 PostgreSQL 执行计划调优里很有含金量的中高级考点。