Featured image of post DuckDB vs PostgreSQL:嵌入式分析与服务端数据库的正面对决

DuckDB vs PostgreSQL:嵌入式分析与服务端数据库的正面对决

DuckDB 和 PostgreSQL 到底该怎么选?从部署复杂度、查询性能、架构设计三个维度实测对比。1000 行数据下 DuckDB 所有查询 3ms 内完成,零配置 vs 5-10 步配置,附完整测试代码和选型建议。

做数据分析这几年,PostgreSQL 一直是"老大哥"般的存在——稳定、强大、生态丰富。但 DuckDB 出来之后,局面开始有点变化了。

这篇文章不打算站队,就想拿数据说话:在数据分析场景下,DuckDB 到底比 PostgreSQL 强在哪?弱在哪?选型的边界到底在哪?

测试环境:macOS,Python 3.12,DuckDB 1.5.2。数据集是 1000 行模拟 NYC 出租车数据。


先搞清楚定位:这俩根本不是同一类东西

很多人一上来就问"DuckDB 能不能替代 PostgreSQL",这个问题本身就问错了。

DuckDB 是 OLAP 数据库,专门为分析型查询设计。列式存储,向量化执行,擅长的是"从 100 万行数据里算出平均值"这种事。

PostgreSQL 是 OLTP 数据库,专门为事务处理设计。行式存储,MVCC 并发控制,擅长的是"100 个用户同时下单,数据不能乱"这种事。

打个比方:DuckDB 是挖掘机,PostgreSQL 是手术刀。你不能用手术刀挖土,也不该用挖掘机做手术。

搞清楚这个前提,后面的对比才有意义。


部署复杂度:一个零配置,一个要命

这是 DuckDB 最让我惊的地方。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# DuckDB:一行搞定
pip install duckdb

# 然后就能用了
import duckdb
conn = duckdb.connect()
result = conn.execute("SELECT 1").fetchall()
```text

没了。真的就这些。从安装到跑出第一条查询,不到 10 秒。

再看 PostgreSQL:

```bash
# 安装
apt install postgresql

# 启动服务
systemctl start postgresql

# 创建用户
sudo -u postgres createuser myuser

# 创建数据库
sudo -u postgres createdb mydb

# 设置密码
psql -c "ALTER USER myuser WITH PASSWORD 'mypass';"

# 配置权限(编辑 pg_hba.conf)
# 重启服务
systemctl restart postgresql
```bash

5-10 步配置,1-5 分钟安装时间。对于没接触过 PostgreSQL 的人来说,光是 `pg_hba.conf` 就能折腾半小时。

| 对比项 | DuckDB | PostgreSQL |
|--------|--------|------------|
| 安装时间 | < 10 秒 | 1-5 分钟 |
| 配置步骤 | 0 步 | 5-10 步 |
| 需要启动服务 | 不需要 | 需要 |
| 存储方式 | 单文件嵌入式 | 独立数据目录 |
| 内存占用 | 按需分配 | 128MB+ 常驻 |

很多项目最后选了 DuckDB 或者 SQLite,不是因为性能更好,纯粹是因为——**部署太简单了**。不需要 DBA,不需要运维,`pip install` 就完事。这个隐藏成本经常被忽略。

---

## 查询性能实测:5 个场景跑一遍

测试数据是 1000 行模拟 NYC 出租车数据,包含上车时间、下车时间、乘客数量、行程距离、费用等字段。

### 测试代码

```python
import duckdb
import time

conn = duckdb.connect()

# 创建测试表
conn.execute("""
    CREATE TABLE trips AS
    SELECT * FROM read_csv_auto('nyc_taxi_1000.csv')
""")

def benchmark(query, name, runs=100):
    # 预热
    conn.execute(query)
    
    times = []
    for _ in range(runs):
        start = time.perf_counter()
        conn.execute(query)
        elapsed = (time.perf_counter() - start) * 1000
        times.append(elapsed)
    
    avg = sum(times) / len(times)
    print(f"{name}: {avg:.2f}ms")
    return avg

# 场景1:基础统计
benchmark("""
    SELECT COUNT(*), AVG(fare_amount), SUM(trip_distance)
    FROM trips
""", "基础统计")

# 场景2:分组聚合
benchmark("""
    SELECT passenger_count,
           AVG(fare_amount),
           SUM(trip_distance),
           COUNT(*)
    FROM trips
    GROUP BY passenger_count
""", "分组聚合")

# 场景3:复杂过滤
benchmark("""
    SELECT * FROM trips
    WHERE fare_amount > 10
      AND trip_distance > 2
      AND passenger_count >= 2
      AND payment_type = 'credit_card'
""", "复杂过滤")

# 场景4:窗口函数
benchmark("""
    SELECT *,
           ROW_NUMBER() OVER (PARTITION BY passenger_count ORDER BY fare_amount DESC)
    FROM trips
""", "窗口函数")

# 场景5:日期分析
benchmark("""
    SELECT DATE_TRUNC('hour', pickup_datetime) AS hour,
           COUNT(*),
           AVG(fare_amount)
    FROM trips
    GROUP BY hour
    ORDER BY hour
""", "日期分析")
```sql

### 测试结果

| 查询类型 | DuckDB 耗时 | 说明 |
|---------|-----------|------|
| 基础统计 | 3.11ms | COUNT / AVG / SUM |
| 分组聚合 | 1.89ms | GROUP BY + 多列聚合 |
| 复杂过滤 | 0.85ms | 多条件 WHERE |
| 窗口函数 | 1.57ms | ROW_NUMBER + PARTITION |
| 日期分析 | 2.00ms | DATE_TRUNC + GROUP BY |

所有查询都在 **3ms 以内**完成。复杂过滤最快(0.85ms),窗口函数也才 1.57ms。

坦白说,1000 行数据量太小,DuckDB 和 PostgreSQL 的性能差距在这里看不出来。根据公开基准测试,数据量到了 10 万行以上,DuckDB 在聚合查询上能快 10-100 倍。列式存储 + 向量化执行的威力,得大数据量才能释放。

---

## 存储空间:小数据量下的反直觉结果

测试完存储空间,结果有点出乎意料:

| 格式 | 大小 |
|------|------|
| Parquet 文件 | 23.09 KB |
| DuckDB 文件 | 524.00 KB |

DuckDB 文件反而比 Parquet 大了 20 多倍?

其实这很正常。DuckDB 文件里不只有数据,还包含索引、元数据、列统计信息。小数据量下这些"基础设施"的开销占比很大。等到数据量到了 10 万行以上,列式压缩的优势才会体现出来,DuckDB 文件会变得比行式存储更紧凑。

---

## 零导入查询:DuckDB 的杀手锏

这个特性每次用都觉得爽:

```python
import duckdb

# 不需要建表,不需要导入,直接查 CSV
result = duckdb.execute("""
    SELECT passenger_count, AVG(fare_amount)
    FROM 'nyc_taxi.csv'
    GROUP BY passenger_count
    ORDER BY AVG(fare_amount) DESC
""").fetchdf()

# 直接查 Parquet
result = duckdb.execute("""
    SELECT * FROM 'data/*.parquet'
    WHERE fare_amount > 100
""").fetchdf()

# 甚至可以直接查远程文件
result = duckdb.execute("""
    SELECT COUNT(*)
    FROM read_parquet('s3://bucket/data/*.parquet')
""").fetchdf()
```sql

不需要 `CREATE TABLE`,不需要 `COPY`,不需要任何预处理。给个文件路径就能查。这在数据探索阶段简直是神器——拿到一份数据,先 `SELECT * FROM 'file.csv' LIMIT 10` 看看长什么样,几秒钟就能开始分析。

PostgreSQL 当然也能做到类似的事(`COPY` 命令、`foreign data wrapper`),但步骤多得多,而且没法直接查 Parquet。

---

## 选型建议:什么时候选谁

说了这么多,到底该怎么选?

### 选 DuckDB 的场景

- **数据分析 / BI 报表**:聚合查询快 10-100 倍
- **快速原型开发**:零配置,`pip install` 就能跑
- **数据探索**:直接查 CSV / Parquet / JSON 文件
- **单机分析**:不需要多用户并发
- **嵌入式分析**:集成到 Python / R 应用里

### 选 PostgreSQL 的场景

- **Web 应用后端**:需要多用户并发读写
- **事务处理系统**:需要 ACID 保证
- **频繁更新场景**:行式存储更新效率高
- **复杂权限管理**:需要细粒度的用户权限控制
- **生产环境**:需要高可用、主从复制、备份恢复

### 两者结合的场景

实际项目里,这俩经常是一起用的:

- PostgreSQL 存业务数据,处理在线事务
- DuckDB 做数据分析,生成报表
- ETL 流程里,PostgreSQL 是源 / 目标,DuckDB 做数据转换

---

## 踩坑记录

### 坑 1:小数据量测试的误导性

1000 行数据跑下来,DuckDB 和 PostgreSQL 的性能差距并不明显。差点就写了"两者性能差不多"的结论。

好在之前看过 DuckDB 的官方基准测试,知道列式存储的优势要在大数据量下才能体现。后来用 10 万行数据复测,聚合查询的差距确实拉开了。

**教训**:数据库性能对比,数据量至少要到 10 万行才有参考价值。

### 坑 2:存储空间对比的误解

看到 DuckDB 文件比 Parquet 大 20 倍的时候,第一反应是"这压缩也不行啊"。

后来仔细看了下 DuckDB 的文件结构,发现 524KB 里有相当一部分是索引和元数据。小数据量下这些固定开销占比很大,数据量上去之后列式压缩的优势才会显现。

**教训**:存储对比不能只看绝对值,要看压缩算法和数据量的关系。

### 坑 3:PostgreSQL 本地测试环境搭建

本地没装 PostgreSQL,本来想装一个跑对比测试。结果 `pg_hba.conf` 配了半天,用户权限搞不清楚,折腾了快一小时。

最后用 Docker 解决了:

```bash
docker run -d --name pg -p 5432:5432 -e POSTGRES_PASSWORD=pass postgres:16
```text

一行命令搞定。如果本地要频繁测试 PostgreSQL,建议直接走 Docker。

---

## 总结

DuckDB 和 PostgreSQL 不是替代关系,是互补关系。

DuckDB 是分析场景的利器——零配置、直接查文件、聚合查询快。PostgreSQL 是事务场景的基石——稳定、并发强、生态成熟。

选型的关键就两条:

1. **你的场景是 OLAP 还是 OLTP?** 分析选 DuckDB,事务选 PostgreSQL
2. **你需要多用户并发吗?** 需要就 PostgreSQL,单机就 DuckDB

如果两个都需要,那就两个都用。它们本来就不是对手,是队友。

---

## 参考资源

- [DuckDB 官方文档](https://duckdb.org/docs/)
- [PostgreSQL 官方文档](https://www.postgresql.org/docs/)
- [DuckDB 论文 (CIDR 2020)](https://hannes.muehleisen.org/publications/CIDR2020-raasveldt-muehleisen-duckdb.pdf)
- [DuckDB vs SQLite 官方对比](https://duckdb.org/2024/01/03/duckdb-vs-sqlite.html)

---

## 延伸阅读

- [DuckDB vs SQLite:选择哪个?](/p/duckdb-vs-sqlite/) - 小数据集 SQLite 快 153 倍,大数据集 DuckDB 快 3.38 倍
- [DuckDB vs Pandas 性能对比:10 万行数据实测](/p/duckdb-vs-pandas/) - 6 个场景实测,DuckDB 平均快 2.3 倍
- [DuckDB 技术栈全解析](/p/duckdb-tech-stack/) - 列式存储、向量化执行引擎原理


一行命令搞定。如果本地要频繁测试 PostgreSQL,建议直接走 Docker。

---

## 总结

DuckDB 和 PostgreSQL 不是替代关系,是互补关系。

DuckDB 是分析场景的利器——零配置、直接查文件、聚合查询快。PostgreSQL 是事务场景的基石——稳定、并发强、生态成熟。

选型的关键就两条:

1. **你的场景是 OLAP 还是 OLTP?** 分析选 DuckDB,事务选 PostgreSQL
2. **你需要多用户并发吗?** 需要就 PostgreSQL,单机就 DuckDB

如果两个都需要,那就两个都用。它们本来就不是对手,是队友。

---

## 参考资源

- [DuckDB 官方文档](https://duckdb.org/docs/)
- [PostgreSQL 官方文档](https://www.postgresql.org/docs/)
- [DuckDB 论文 (CIDR 2020)](https://hannes.muehleisen.org/publications/CIDR2020-raasveldt-muehleisen-duckdb.pdf)
- [DuckDB vs SQLite 官方对比](https://duckdb.org/2024/01/03/duckdb-vs-sqlite.html)

---

## 延伸阅读

- [DuckDB vs SQLite:选择哪个?](/p/duckdb-vs-sqlite/) - 小数据集 SQLite 快 153 倍,大数据集 DuckDB 快 3.38 倍
- [DuckDB vs Pandas 性能对比:10 万行数据实测](/p/duckdb-vs-pandas/) - 6 个场景实测,DuckDB 平均快 2.3 倍
- [DuckDB 技术栈全解析](/p/duckdb-tech-stack/) - 列式存储、向量化执行引擎原理
Built with Hugo
Theme Stack designed by Jimmy