在PostgreSQL中,优化器依靠统计信息来估算查询代价并生成执行计划。默认情况下,系统只为每张表收集单列的统计信息,当多个列之间存在强相关性时,单列统计会导致选择率估算严重偏差。自定义统计信息正是为解决这一痛点而引入的机制,它允许开发者显式声明需要联合分析哪些列,从而让规划器理解列间依赖或联合分布。

为什么需要自定义统计信息
假设有一张用户行为表,其中城市与省份两列显然高度相关。如果只使用默认统计,优化器会认为city = '杭州'和province = '浙江'是两个独立事件,将选择率相乘,结果远远小于真实值。这种低估会使优化器错误地选择嵌套循环而非哈希连接,最终查询变慢。
从PostgreSQL 10开始,系统支持通过CREATE STATISTICS创建扩展统计对象。它不改变数据存储,只影响ANALYZE采样的计算方式。对于宽表、维度退化模型或报表类查询,自定义统计信息是性价比极高的优化手段,不需要改表结构,也不用强行建组合索引。
自定义统计信息的类型
目前主要支持三类扩展统计:单列统计是默认行为;依赖统计(dependencies)记录列间函数依赖,适合A决定B的场景;多维分布统计(ndistinct)记录多列组合的不同值数量;表达式统计则可针对计算列收集信息。最常用的是依赖与ndistinct。
| 类型 | 关键字 | 适用场景 |
|---|---|---|
| 依赖统计 | dependencies | 列间强相关,如省市区 |
| 不同值统计 | ndistinct | 估算多列组合唯一度 |
| 表达式统计 | expressions | 函数结果的选择率 |
创建依赖统计示例
以下语句为orders表的customer_id与region列建立依赖关系统计:
CREATE STATISTICS orders_cust_region_deps (dependencies) ON customer_id, region FROM orders; ANALYZE orders;
执行后,规划器在见到同时过滤这两列的条件时,不会再简单相乘选择率。可以通过EXPLAIN对比前后计划,通常能看到估算行数更接近真实返回。
创建多维不同值统计
当需要知道多列组合去重数时,使用ndistinct:
CREATE STATISTICS orders_combo_nd (ndistinct) ON user_id, product_id FROM orders; ANALYZE orders;
这类统计对GROUP BY多列或DISTINCT多列的查询尤其有用,能避免优化器高估聚合后的行数,从而更合理地选择哈希聚合或排序聚合。
查看与维护
自定义统计对象存储在pg_statistic_ext系统表中,可用如下语句检查:
SELECT stxname, stxkeys, stxkind FROM pg_statistic_ext WHERE stxrelid = 'orders'::regclass;
统计不会自动随数据变化更新,必须定期对被统计表执行ANALYZE,或配置自动清理参数让系统更积极采样。删除时用DROP STATISTICS语句即可,不会影响原表数据。
合理使用自定义统计信息,是在不改动业务SQL的前提下修正执行计划的有效方式。建议先通过EXPLAIN (ANALYZE, BUFFERS)定位估算偏差,再针对性建统计对象,最后以真实负载验证效果。
PostgreSQL自定义统计信息查询优化修改时间:2026-08-11 20:24:23