You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL负n_distinct值行为与文档描述不符的技术疑问

PostgreSQL负n_distinct值的行为解析:表规模不影响单值估计行数的原因

核心逻辑拆解

PostgreSQL对负n_distinct的定义包含两个关键规则:

当设置为大于等于-1的负值时,ANALYZE会假设列中非空不同值的数量与表大小呈线性关系;具体数值为估计表大小乘以给定数值的绝对值。例如,值为-1表示列中所有值均唯一,值为-0.5表示每个值平均出现两次。

结合查询规划阶段的行数计算逻辑,可推导出单值估计行数的公式:

  1. 不同值数量 = 表行数 × |n_distinct|
  2. 单值估计行数 = 表行数 ÷ 不同值数量

将两个公式合并后,表行数会被抵消:
单值估计行数 = 表行数 ÷ (表行数 × |n_distinct|) = 1/|n_distinct|

这就是表规模变化不影响单值估计行数的原因——最终结果仅由n_distinct的绝对值决定,和表行数无关。

对应测试验证

你的测试结果完全匹配上述逻辑:

  • 当n_distinct=-0.5时,1/0.5=2,所以无论表是10000行还是510000行,查询select * from tab where a = 5的估计行数均为2,和文档中“每个值平均出现两次”的描述完全一致。
  • 当n_distinct=-0.001时,1/0.001=1000,两种表规模下估计行数均为1000,符合计算结果。

对比正数n_distinct的场景(如设为20),此时不同值数量被固定为20,单值估计行数为10000/20=500,这是固定不同值数量的静态计算,和负数的动态比例逻辑本质不同。

测试代码复现

create table tab(a int);

insert into tab select * from generate_series(1,10000);

analyze tab;
explain select * from tab where a = 5;
-- Correctly estimates 1 row
--Seq Scan on tab  (cost=0.00..170.00 rows=1 width=4)
--  Filter: (a = 5)

alter table tab alter column a set (n_distinct = 20);  

analyze tab;
explain select * from tab where a = 5;
-- Correctly estimates 1000/20 = 500 rows
--Seq Scan on tab  (cost=0.00..170.00 rows=500 width=4)
--  Filter: (a = 5)

alter table tab alter column a set (n_distinct = -0.5); 

analyze tab;
explain select * from tab where a = 5;
--Seq Scan on tab  (cost=0.00..170.00 rows=2 width=4)
--  Filter: (a = 5)

alter table tab alter column a set (n_distinct = -0.1); 

analyze tab;
explain select * from tab where a = 5; 
--Seq Scan on tab  (cost=0.00..170.00 rows=10 width=4)
--  Filter: (a = 5)

alter table tab alter column a set (n_distinct = -0.001); 

analyze tab;
explain select * from tab where a = 5;   
--  Seq Scan on tab  (cost=0.00..170.00 rows=1000 width=4)
--  Filter: (a = 5)

insert into tab select * from generate_series(10001,500000);

alter table tab alter column a set (n_distinct = -0.5); 

analyze tab;
explain select * from tab where a = 5;
--Gather  (cost=1000.00..6889.67 rows=2 width=4)
--  Workers Planned: 1
--  ->  Parallel Seq Scan on tab  (cost=0.00..5889.47 rows=1 width=4)
--        Filter: (a = 5)

alter table tab alter column a set (n_distinct = -0.001); 

analyze tab;
explain select * from tab where a = 5;
--Gather  (cost=1000.00..6989.47 rows=1000 width=4)
--  Workers Planned: 1
--  ->  Parallel Seq Scan on tab  (cost=0.00..5889.47 rows=588 width=4)
--        Filter: (a = 5)

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:45:33