博客

和 PostgreSQL 的二十年·5 篇,共 7

同一个数据库,不同的用法

Cover Image for 同一个数据库,不同的用法

我第一次用 PostgreSQL 做数据分析,是 2016 年在一家广告公司。

原因很简单:它在,其他的不在。

ClickHouse 那年刚开源,还没到能用的程度。Hadoop 搭起来没个把月下不来,太庞大。手边有一个 PG 实例和一块 1T SSD,产品经理在等数据。那就 PG 吧,先跑起来再说。

那次其实跑得很费劲。Mac 笔记本,早期 SSD,不是今天的 NVMe,PG 在上面挣扎着跑,磕磕绊绊。

但业务不等人。新业务线,新产品,infra 的大数据组支持还没到位,我作为技术负责人,所有悬而未决的问题都会自动指向我。能力也是有限的,手边只有这个,那就让它跑。跑完了,数据出来了,能交差就行。

能用 PG 还有一个前提:raw log 能从生产服务器拿下来。

这件事听起来简单,但几年前根本不可能——生产是黑盒,开发没有权限,更别说打包拖数据了。2016 年能拿到,一部分是 DevOps 文化兴起的背景,但说实话,更直接的原因是做到了足够高的职位,业务压着要数据,没有人敢跟你说走流程。权限这件事,有时候不是技术问题,是组织问题。

如果当时我在大数据组,答案大概是 Hadoop + Spark。如果还在外包团队的底层,raw log 拿不到,这条路也走不通。放到今天,DuckDB 直接读 log 文件,五分钟出报表,什么都不用搭。

时代的局限、个人的位置、手边的工具——三个变量同时决定了技术选型。不是最好的方案,是当时能用的方案。这件事我后来想了很久才想明白。

后来换了一家同时做数字广告和金融业务的公司,从头搭系统,数据量上了一个量级,PG 做分析这条路才真正开始走不通。


那是一套从头搭起来的系统。OLTP 用 PostgreSQL,这没什么好说的,多年来的习惯,也是正确的选择。问题出在 OLAP 这一侧——广告业务有大量的聚合查询需求,金融业务有实时计费,数据量还在快速膨胀。

最初的方案是 PostgreSQL 一把抓,OLTP 和 OLAP 都压在它身上。

很快就撑不住了。

聚合查询慢。磁盘占用飞速膨胀,随随便便就吃掉 500GB,还在涨。最要命的是数据更新——核心业务表的数据量到了百亿级别,全量 upsert 一次,PostgreSQL 自己来做,需要 48 小时

48 小时。两天。

这不是性能问题,这是架构问题。


第一个缺口,是 ClickHouse 补上的。

实时计费这条线抽出来,由 API 日志实时摄入 ClickHouse,聚合查询直接走它。ClickHouse 的列存和向量化执行为此而生,把这件事还给它,PG 立刻轻松了一大块。

但磁盘问题还在,upsert 问题还在。


磁盘的解法来自一个意外。

当时的思路是研究存算分离方案——类似 TiDB 的架构,把存储层和计算层拆开,从软件层面解决磁盘瓶颈。方向是对的,但代价也很清晰:分布式系统的运维复杂度、团队学习成本、在本来就资源紧张的服务器上跑分布式集群的风险。

还没想清楚怎么落地,无意间发现了 ScaleFlux

ScaleFlux 做的是计算型存储——SSD 里内置了压缩/解压缩引擎,数据写进去之前在硬件层透明压缩,读出来之前透明解压,上层软件完全无感。压缩率大概能到 30% 左右,和 btrfs 文件系统压缩的效果相近,但是纯硬件方案,没有 CPU 开销,没有软件改动,PostgreSQL 还是那个 PostgreSQL。

我们联系了厂家,请销售带着样品来做 PoC,实测下来数据和标称的基本吻合。

最后的决定很简单:换一块盘,磁盘问题解决了,架构什么都不用动。 (想的美,预算申请不到,最后还是 CPU 默默的扛下了一切)

本来打算造的轮子,一块硬盘替代了。最好的架构决策有时候不是加东西,而是发现可以不加什么。


upsert 的问题,解法同样不在 PostgreSQL 里。

百亿行的表,与其让 PostgreSQL 自己做 upsert——逐行比对、加锁、写 WAL、更新索引——不如换一个思路:让专门的工具做完计算,PostgreSQL 只负责接收结果。

DuckDB 在这里扮演了 ETL 引擎的角色。

它利用服务器的多核 CPU 并行处理,在内存里完成所有的聚合和合并计算,最后把结果一次性导入 PostgreSQL 重建表。绕开了 PostgreSQL 逐行 upsert 的瓶颈,也绕开了锁争用和 WAL 膨胀。

同样的数据量,同样的服务器,48 小时压缩到了 2 小时

DuckDB 没有替换 PostgreSQL,它是外挂的。PostgreSQL 继续承担 100 亿行数据的 API 查询,靠索引在性能孱弱、资源紧张的服务器上撑住了 API 的响应时间。两个工具各做各擅长的事,组合起来比任何单一方案都好。


最后这套架构长这样:

  • ClickHouse:实时计费,API 日志流式摄入,聚合查询
  • PostgreSQL:百亿行 OLTP,API 查询底层,索引支撑
  • DuckDB:外挂 ETL 引擎,批量 upsert,多核并行
  • ScaleFlux:硬件压缩层,透明解决磁盘膨胀

没有哪一个是银弹。每个工具都只做它最擅长的那一件事,裂缝由另一个工具来填。


这段经历让我对"PostgreSQL 不适合做 OLAP"这个说法有了更复杂的理解。

它确实不适合——聚合查询慢、磁盘占用大、大规模 upsert 代价高昂。这些不是偏见,是真实的限制。

但"不适合"不等于"不能用"。在具体的约束条件下,你手里的工具、团队的熟悉程度、运维的复杂度预算,这些因素加在一起,有时候"不适合"的方案反而是最优解——只要你知道它的边界在哪里,知道怎么在边界之外补上缺口。

DuckDB 是缺口。ScaleFlux 是缺口。ClickHouse 也是缺口。

PostgreSQL 还是那个 PostgreSQL,只是它不用再一个人扛所有的事了。


对了,当初那个拒绝加入数据仓库团队的决定——就是第一篇里提到的,那个我一口回绝的机会。

后来那个团队发展得很好。

命运呐。