DuckDB — 把 OLAP 数据库塞进你的 Python 进程
是什么
DuckDB 是一个嵌入到你程序里跑的分析数据库。日常类比:SQLite 是给笔记应用用的”装在 App 内的小数据库”,但它专门擅长一行一行处理;DuckDB 是它的”分析师亲戚”——一样塞进进程内、不需要起服务器,但专门擅长一列一列扫几百万行做汇总。
你写:
import duckdbduckdb.query("SELECT category, AVG(price) FROM 'sales.parquet' GROUP BY category").df()没有连接字符串、没有起服务、没有 docker。这一行代码读了 1GB Parquet 文件,做了分组聚合,把结果给回 Pandas DataFrame。
这个”嵌入式 + 专做分析”的组合是 DuckDB 的核心定位——SIGMOD 2019 论文叫它 “OLAP 版的 SQLite”。
为什么重要
不理解 DuckDB 的设计动机,下面这些事会觉得奇怪:
- 为什么 2024 年 Pandas 用户开始集体迁移过去——明明 Pandas 已经够用了
- 为什么 Notebook 里跑个 SQL 不需要先连 PostgreSQL
- 为什么同样一份 Parquet,DuckDB 比 SQLite 快 50 倍
- 为什么数据工程师面试现在会问 “向量化执行 vs 火山模型 (Volcano) 区别”
数据科学日常痛点是:数据 1-100GB 这一档——比 Pandas 内存放得下的大、比上 Spark 集群划得来的小。DuckDB 就是为这一档生的。
核心要点
DuckDB 三个支柱合起来才解释它为什么快又好用:
-
列式存储(columnar):表在磁盘和内存里按”列”存,不是按”行”。类比:Excel 把一整列工资数字连续放在一起,求平均时只扫这一列、不会顺路读姓名地址。这是分析查询能压缩、能向量化的前提。
-
向量化执行(vectorized execution):每次操作处理一个 “vector”(≈ 1024-2048 个值的小批),而不是火山模型那样一次一行。类比:搬砖时一次抱 2000 块(vector)效率远高于一次抱 1 块(row)也远好于一次抱 100 万块(column-at-a-time,缓存装不下)。这一招出自 monetdb-x100-2005。
-
嵌入式 in-process:DuckDB 是一个 .so / .dll 库,被你 Python / R / C++ 进程直接 link。不像 PostgreSQL 要起 daemon,调用就是普通函数,零网络开销。
加上 ACID 事务(自定义 MVCC)、SQL-92 大部分支持、可直接读 Parquet/CSV/Arrow。
一图看懂三层结构
你的 Python 程序进程┌──────────────────────────────────┐│ Pandas / PyArrow / 业务代码 ││ ↕ 零拷贝(同进程) ││ ┌──────────────────────────────┐ ││ │ DuckDB 查询引擎 │ ││ │ ├─ SQL parser + 优化器 │ ││ │ ├─ vectorized executor │ ││ │ └─ MVCC 事务 │ ││ └──────────────────────────────┘ ││ ↕ ││ ┌──────────────────────────────┐ ││ │ 列式存储 (单文件 .duckdb) │ ││ │ 也能直接读 Parquet/CSV/Arrow │ ││ └──────────────────────────────┘ │└──────────────────────────────────┘注意整个数据库是进程内的几个对象,不是另一个服务。
实践案例
案例 1:Pandas DataFrame 当 SQL 表查
import duckdbimport pandas as pddf = pd.read_csv("orders.csv")result = duckdb.query("SELECT user_id, SUM(amount) FROM df GROUP BY user_id").df()注意:df 直接出现在 SQL 里——DuckDB 在同一进程里能”看见”Python 变量。没有任何数据复制,DuckDB 直接读 Pandas 内存。这是嵌入式带来的核心便利。
案例 2:直接查 Parquet 文件
duckdb.query("SELECT * FROM 'data/2024-*.parquet' WHERE region='APAC'").df()DuckDB 边读边过滤(predicate pushdown),只解码需要的列(projection pushdown)。1GB 文件可能只读出几十 MB。中等规模 ETL 任务可以替代 Spark。
案例 3:CLI 当本地数据治理工具
duckdb -c "SELECT count(*), region FROM read_csv('logs.csv') GROUP BY region"像 awk / jq 一样在命令行里写 SQL 处理本地文件,不开 Python 也行。
案例 4:Wasm 浏览器内分析
DuckDB 编了 Wasm 版本,可以在浏览器里直接跑分析查询。OpenAI 的某些数据看板、Hugging Face datasets 预览都用了它。这是真正”嵌入式”的极限——连服务器都没有。
踩过的坑
-
当 OLTP 数据库用就翻车:DuckDB 是单写多读的 OLAP 引擎,并发写入吞吐远不如 PostgreSQL/MySQL。Web 后端用户表请用别的,DuckDB 适合分析查询。
-
超出单机就该换工具:DuckDB 是单机嵌入式,没有分布式。数据量稳定超过几百 GB、需要副本/分片,就该上 ClickHouse / Snowflake。
-
以为”列存自动比行存快”:列存只在大量行扫描+少数列聚合时占优。点查询(按主键取一行)反而行存更快。要看负载选工具。
-
大文件没设并发:默认 threads 数有时候不够。
SET threads TO 8一行让查询快几倍,但容易忘。 -
嵌入式 ≠ 玩具:很多人看到”单文件、单进程”就以为像 SQLite 一样只能跑小数据。实际 DuckDB 在 100GB Parquet 上常规聚合也能秒级返回。
适用 vs 不适用
适用:
- Notebook / 脚本里做 SQL 分析(取代 Pandas + 取代起 PG)
- 中等规模 ETL(GB 到 TB 之间,单机磁盘装得下)
- 嵌入到桌面 / 移动 / Wasm 应用做本地分析(单文件库,跨平台)
- 直接读 Parquet/Arrow 做数据科学预处理
不适用:
- 高并发 OLTP 写入(用 PostgreSQL / MySQL)
- 分布式大数据(用 ClickHouse / Snowflake / BigQuery)
- 需要严格服务隔离/多租户(嵌入式天然没隔离)
- 全文搜索(用 Elasticsearch / Postgres FTS)
历史小故事(可跳过)
- 2005 年:CWI 数据库组在 monetdb-x100-2005 论文提出”向量化执行”,证明可以比一次一行快十倍以上,后来商业化为 Vectorwise。
- 2017 年:Hannes Mühleisen 在 R 社区做 MonetDBLite——把 MonetDB 改成嵌入式版本——发现 MonetDB 太重、不适合嵌入。
- 2018 年:Mühleisen 与博士生 Mark Raasveldt 决定从零开始写一个嵌入式分析数据库,吸收 MonetDB/X100 向量化思路。命名 DuckDB(CWI 园区有只鸭子吉祥物 Wilbur)。
- 2019 年:SIGMOD 2019 demo 论文(4 页)发布。
- 2020 年:CIDR 2020 全文版进一步阐述存储与执行。
- 2022 年:成立 DuckDB Labs(开源 + 商业支持双轨)。
- 2024 年:在 Python 数据栈生态里成为最常用嵌入式分析引擎,Pandas 用户大规模迁移。
学到什么
- 嵌入式不等于小:SQLite 让人觉得嵌入式 = 玩具,DuckDB 用 100GB 级数据证明嵌入式可以是认真的分析工具。
- 列式 + 向量化是一对:单独列式(C-Store)和单独向量化(早期 Vectorwise)都厉害,但 DuckDB 把两者工程化合在一起塞进库里才真正普及。
- 找对部署摩擦的痛点:DuckDB 的最大胜利不是性能而是”不用起服务”——降低部署门槛常比性能优化收益更大。
- 学院派也能赢工程:CWI 这种研究机构持续 20 年(MonetDB → X100 → MonetDBLite → DuckDB)演进同一思路,最终改变了一个生态。
延伸阅读
- 官方主页:duckdb.org — 入门 5 分钟
- 论文 PDF:DuckDB SIGMOD 2019 demo(4 页,密度高)
- 长版论文:DuckDB CIDR 2020(讲存储格式、MVCC 实现)
- 视频:Hannes Mühleisen 在多个数据库会议讲 DuckDB 设计取舍,YouTube 搜 “DuckDB Hannes” 即可
- monetdb-x100-2005 —— DuckDB 向量化执行的思想源头
- volcano-1994 —— 火山模型,一次一行的迭代器,DuckDB 用 vector 替换了”行”
- cstore-2005 —— Stonebraker 列存原创论文,DuckDB 存储设计的另一支祖先
关联
- monetdb-x100-2005 —— 向量化执行的开山之作,DuckDB 直接继承
- volcano-1994 —— pull-based 迭代器模型,DuckDB 在它基础上把粒度改成 vector
- cstore-2005 —— 列存数据库经典,DuckDB 存储格式的祖先
- vertica-2012 —— C-Store 商业化,列存在工业界的代表
- snowflake-2016 —— 云上分布式 OLAP,与 DuckDB 互补(云 vs 嵌入式)
- leis-2015-optimizers —— 现代查询优化器评测,DuckDB 的优化器吸收了这条线
- stonebraker-2010-sqlnosql —— 同期数据库格局讨论