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

Postgres从pg_stats查询列非空去重估计值为负数问题排查

PostgreSQL查询pg_stats返回负数distval问题解答

错误根源

你查询返回负数的核心原因是对pg_stats系统表中n_distinct字段的官方定义理解有误:

  • 当n_distinct为正数时,才代表该列预估的固定非空去重值数量
  • 当n_distinct为负数时,其绝对值代表该列预估的非空去重值占表总行数的比例。比如你拿到的-0.86514354,就代表该列去重值约等于表总行数的86.5%,PostgreSQL返回负数的场景通常是表数据仍在持续增长,优化器判定该列去重值会随表行数同步增长,不会固定为某一常量。

修正方案

要得到正整数格式的distval,你需要关联pg_class系统表拿到对应表的预估行数reltuples,根据n_distinct的正负做换算即可,修正后的查询语句如下:

SELECT 
    s.tablename,
    s.attname,
    -- 根据n_distinct的正负换算得到正整数格式的去重值预估值
    CASE 
        WHEN s.n_distinct > 0 THEN s.n_distinct::bigint
        ELSE ABS(s.n_distinct) * c.reltuples::bigint
    END AS distval,
    (s.histogram_bounds::text::varchar[])[1] AS min,
    (s.histogram_bounds::text::varchar[])[array_upper(s.histogram_bounds::text::varchar[], 1)] AS max
FROM pg_stats s
INNER JOIN information_schema.columns col 
    ON s.tablename = col.table_name 
    AND s.attname = col.column_name
INNER JOIN pg_class c 
    ON c.relname = s.tablename
    AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = s.schemaname)
WHERE 
    NOT (col.table_schema LIKE 'pg_%' OR col.table_schema = 'information_schema')
    AND col.data_type = 'character varying'
    AND col.table_name NOT IN (SELECT viewname FROM pg_views)
LIMIT 5;

补充说明

  • 上述计算得到的distval是PostgreSQL基于统计信息生成的预估值,不是精确计数,要提升准确性可以先执行ANALYZE 你的表名更新统计信息
  • 原查询使用的隐式连接逻辑已替换为显式INNER JOIN,可读性和可维护性更好

内容的提问来源于stack exchange,提问作者Anđela Todorović

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:36:03