DeepSeek总结的postgresql 数据分析师 vs width_bucket() 来源https://kmoppel.github.io/2026-05-21-data-analyst-vs-width-bucket/postgresql 数据分析师 vs width_bucket()发表于2026年5月21日在帮助一位头衔为“数据分析师”的朋友解决了一些轻量级的 Postgres “分桶”bucketing难题之后——考虑到这并非多年来该领域第一次出现这种情况我想着也为未来的谷歌搜索者/LLM 用户们提供一些帮助因为我见过太多针对这个相对基础的任务即以一种简单且易于理解的视觉表示来理解数值列的数据分布所采用的奇怪且低效的解决方案。变通方法想想这样的做法将整列数据导出到一个文本文件然后加载到 Jupyter notebook 的 dataframe 中同时祈祷一切能适应内存且不会崩溃……基本上需要的是快速的 SQL 来生成一个漂亮、可读的“直方图”类型的表示要求如下快速即完全在数据库内部运行并最小化重复/重扫视觉上易懂没有不需要的额外桶除了桶计数外数值范围也应可见“默认”分桶的问题默认的width_bucket()实现有什么问题简而言之——对于运行时计算的 min/max它会产生一个包含一个值的额外桶行关于此可参阅此处 Postgres 源代码的注释和理由在实践中这对于数据整理者来说似乎是多余/令人困惑的……当然可以通过一点额外的 SQL 来解决这个问题……就像 SQL 一贯的情况一样正如我在下面的实现中所做的那样。但另一方面还缺少视觉表示和值范围指示……为了视觉指示默认用法看起来像这样[此处假设有图片默认 width_bucket 用法]顺便说一句如果使用带有数组输入的第二种width_bucket()形式额外的桶问题会自动消失。然而这种路径在网上似乎并不那么流行——可能是因为它会导致更长的 SQL……出于好玩我自己也亲身体验了一下 因此为了解决这些问题请在下面找到一个改进版的width_bucket()可能还可以进一步简化它基于始终有用的 “pgbench” 模式并在第一个 CTE 中设置了易于配置的桶数和最大“条形图”宽度。用于简单等分块和快速分桶的 SQLWITHq_bucketsAS(SELECT10ASbuckets,100ASmax_bar_width,■ASbar_char),q_boundsAS(SELECTmin(abalance)ASmin_val,max(abalance)1ASmax_val-- 为了避免额外的桶FROMpgbench_accounts),q_bucketedAS(SELECTwidth_bucket(abalance,(selectmin_valfromq_bounds),(selectmax_valfromq_bounds),(selectbucketsfromq_buckets))ASbucket,count(*)ASbucket_items,min(abalance)ASbucket_min,max(abalance)ASbucket_maxFROMpgbench_accountsGROUPBY1ORDERBY1),q_bucketed_range_correctedAS(SELECTbucket,bucket_items,-- case when 用于恢复正确的最后一个桶的上限值int4range(bucket_min,casewhenbucket(selectbucketsfromq_buckets)thenbucket_max-1elsebucket_maxend,[])asrangeFROMq_bucketed)SELECTbucket,range,bucket_items,repeat((SELECTbar_charFROMq_buckets),(bucket_items::numeric/(SELECTmax(bucket_items)FROMq_bucketed)*(SELECTmax_bar_widthFROMq_buckets))::int)AScount_as_barFROMq_bucketed_range_corrected;执行后会产生类似这样的结果[此处假设有图片改进后的 width_bucket 直方图]更好的未来顺便说一下这个问题空间对其他人来说似乎也并非未知一些 Postgres 博客以前也提到过例如这里和这里早在 2014 年所以也许确实有些事情本应更容易但实际并非如此。请注意后者提供了一个非常简洁的短 SQL但它再次带来了这个烦人的“低于下限”的额外桶问题。因此从这个例子中可能可以得出的另一个结论是如果 Postgres 能为一些典型的即席/探索性数据探查任务提供更多便利函数那将是非常好的至少对数据分析师/科学家来说这似乎是目前的一个弱点。嗯至少与一些较新的数据库如 DuckDB 和 Clickhouse 相比是这样这些数据库在诸如直方图、统计分析/汇总以及廉价的内置近似“top-k”和“approx_count_distinct”类型函数估计等主题上有更多便利函数可用而 Postgres 通常需要第三方扩展这些扩展在大多数托管服务提供商上又不可用或一些更复杂的技巧如触发器。PS - LLM在以正确的方式提问并进行一点纠正后似乎也能够生成类似于上面的 SQL——但根据我的测试它们的实现速度大约慢 3 倍Claude到 10 倍ChatGPT原因是未知的所以要小心……PS2 还有——它们太轻率地推荐重新利用内部pg_stats.most_common_freqs数据——但再次提醒要小心因为此路径仅在你感兴趣的列没有最常见的值或者它们非常分散时才应使用但确实——在某些情况下它可能有用并且人们可以相对容易地将内置直方图顺便说一句在大型表上使用默认的“统计目标”设置时它可能非常不具有代表性转换为视觉上更易理解的东西……我想只有在统计目标接近默认值 100 时才能实现这一点。像往常一样免费的午餐可没那么容易 SELECTord,valFROMpg_stats,LATERAL unnest(histogram_bounds::text::int[])WITHORDINALITYASt(val,ord)WHEREattnameabalance;希望有一天能对某人有所帮助标签:postgres sql analytics data science