五年前,我接手一个数据分析项目。当时的选择很自然:PostgreSQL。
理由很充分:稳定、功能全、社区大、文档好。用了五年,没出过大问题。查询性能也够用,加几个索引,大部分查询都能在1秒内返回。
直到去年,数据量从100万行涨到1亿行。
PostgreSQL开始吃力了。一个复杂的聚合查询,以前1秒,现在要30秒。加了索引也没用,因为查询逻辑太复杂,索引帮不上忙。
我开始找替代方案。然后遇到了DuckDB。
PostgreSQL的问题
先说清楚,PostgreSQL是好数据库。真的。
它的强项是OLTP(在线事务处理):高并发、短事务、数据一致性。电商订单、用户系统、支付流水,这些场景PostgreSQL是王者。
但数据分析是OLAP(在线分析处理):低并发、长查询、大量扫描。这两个场景的需求完全不一样。
OLTP需要快速响应单个请求,所以用行式存储,一行数据连续存放。OLAP需要快速扫描大量数据,所以用列式存储,一列数据连续存放。
PostgreSQL是行式存储。当你做SELECT AVG(salary) FROM users WHERE dept = 'eng'时,它要把整行数据都读进来,即使你只需要salary和dept两列。
数据量小的时候,这个开销可以忽略。数据量大了,就是瓶颈。
DuckDB的优势
DuckDB是列式存储,专为OLAP设计。
同样的查询,DuckDB只读salary和dept两列,其他列完全不碰。性能差距是数量级的。
我做了个测试:1亿行数据,计算每个部门的平均工资。
PostgreSQL(加了索引):28秒 DuckDB:1.2秒
23倍的性能差距。
而且DuckDB是进程内数据库,不需要单独的服务。直接嵌入Python,像pandas一样用。没有网络开销,没有连接池,没有服务管理。
这种体验,PostgreSQL给不了。
不是替代,是互补
我不是说DuckDB要替代PostgreSQL。
生产系统的订单数据,我还是用PostgreSQL。需要事务、需要并发、需要外键约束,这些DuckDB都不擅长。
我的用法是:PostgreSQL存生产数据,DuckDB做数据分析。
每天凌晨,把PostgreSQL的数据导出成Parquet文件,导入DuckDB。白天的分析查询都在DuckDB上跑,不影响生产系统。
这种架构有个好处:分析查询再重,也不会拖慢线上服务。以前在PostgreSQL上跑复杂查询,经常被投诉"系统卡了"。现在分析查询在DuckDB上跑,PostgreSQL专心处理事务,两边互不干扰。
迁移成本
迁移成本比我想象的低。
DuckDB支持标准SQL,大部分PostgreSQL的查询可以直接跑。只有少数函数不兼容,比如PostgreSQL的generate_series,DuckDB用generate_subscripts。
数据迁移更简单。DuckDB可以直接读PostgreSQL的导出文件,甚至可以直接查询PostgreSQL(通过postgres扩展)。
不过我不建议直接查生产库,还是导出成Parquet比较稳。
踩过的坑
用了半年DuckDB,踩了几个坑。
坑1:并发写入
DuckDB不支持高并发写入。它是单_writer模型,同一时间只能有一个写入操作。如果你的场景需要多个进程同时写入,DuckDB不适合。
我的解决方案:写入还是用PostgreSQL,DuckDB只读。
坑2:内存管理
DuckDB默认用系统内存的70%。如果数据量太大,会OOM。可以设置memory_limit参数,但超过内存的数据得用磁盘溢出,性能会下降。
我现在的做法:分析之前先估算数据量,超过内存的就分块处理。
坑3:持久化
DuckDB可以持久化到文件,但不如PostgreSQL成熟。没有WAL、没有流复制、没有时间点恢复。
所以我不把DuckDB当主数据库用。它只是个分析引擎,数据丢了可以重新从PostgreSQL导入。
适用场景
用了半年,我总结了DuckDB的适用场景。
适合DuckDB:
- 数据分析、报表生成
- 数据探索、快速原型
- 数据管道中的转换步骤
- 单机分析,不需要分布式
适合PostgreSQL:
- 生产系统的事务处理
- 高并发读写
- 需要强一致性
- 需要复杂的权限管理
两者结合:
- PostgreSQL存生产数据
- DuckDB做数据分析
- 定期同步,互不干扰
性能对比
做个全面的性能对比。测试环境:1亿行数据,4核CPU,16GB内存。
查询1:简单聚合
| |
- PostgreSQL: 28秒
- DuckDB: 1.2秒
查询2:多表JOIN
- PostgreSQL: 45秒
- DuckDB: 3.8秒
查询3:窗口函数
- PostgreSQL: 32秒
- DuckDB: 2.1秒
查询4:时间序列聚合
- PostgreSQL: 38秒
- DuckDB: 1.8秒
所有查询,DuckDB都快10-20倍。
给PostgreSQL用户的建议
如果你也在用PostgreSQL做分析,几点建议:
别急着迁移。 先搞清楚你的瓶颈是什么。如果是查询慢,试试DuckDB。如果是并发高,PostgreSQL是对的。
混合使用。 不用二选一。PostgreSQL做事务,DuckDB做分析,各司其职。
先小规模测试。 别一上来就迁移整个系统。先拿一个分析场景测试,看看效果。
注意内存。 DuckDB吃内存,大数据集要提前规划。
学习成本很低。 DuckDB的SQL和PostgreSQL几乎一样,学习成本可以忽略。
最后
从PostgreSQL到DuckDB,不是技术升级,是场景适配。
PostgreSQL是OLTP的王者,DuckDB是OLAP的新秀。两者不是竞争关系,是互补关系。
用了半年,我的感受是:分析查询终于不用等了。以前跑个复杂查询要去喝杯咖啡,现在几秒钟出结果。这种体验,一旦习惯了,就回不去了。
如果你也在用PostgreSQL做分析,试试DuckDB。不是替代,是互补。
