DuckDB指南:43k星嵌入式分析数据库,一行SQL直接查CSV和Parquet

项目:duckdb/duckdb | 星数:42674 | 语言:C++ | 协议:MIT | GitHub仓库

更新日期:2026-10-30 · 作者:CodeArts 编辑部

一个 300MB 的 CSV 把我逼去用了 DuckDB

上个月运营发来一个 300MB 的订单导出文件,让我算"每个省份、每个品类、每个月的复购率"。用 pandas 打开,内存直接吃到 6GB,机器开始卡;导进 MySQL 光建表和导入就花了二十分钟。后来同事扔给我一句:用 DuckDB 试试。装完 pip,一行 SQL 直接读 CSV 出结果,全程不到十秒。

DuckDB 是 42674 星的嵌入式分析数据库,MIT 协议,C++ 实现。它没有服务器——进程内运行,像 SQLite 一样简单,但面向的是分析型(OLAP)场景:列式存储、向量化执行、自动并行。

OLTP 与 OLAP:为什么不能只用一个库

维度SQLite / MySQL(OLTP)DuckDB(OLAP)
存储布局行式列式
擅长按主键读写单行全表聚合、大范围扫描
索引B+ 树为主按需建,更依赖列存与压缩
典型查询查订单详情算月度 GMV 环比
并发写支持单写多读

搞清这条分界,就不会拿 DuckDB 当业务后端。它适合的是「读一大片数据做统计」,不适合「高频小事务」。用它替代线上订单库一定会出事。

安装与最快的一次查询

# Python
pip install duckdb

# 命令行
brew install duckdb      # macOS
winget install DuckDB.cli  # Windows

# 一条命令直接查 CSV,不需要建表
duckdb -c "SELECT province, sum(amount) FROM read_csv_auto('orders.csv') GROUP BY 1 ORDER BY 2 DESC LIMIT 10"

read_csv_auto 会自己推断表头和类型,read_parquet、read_json_auto、Excel 同理。这一点非常省事——临时分析根本不用先建 schema。

三个日常最实用的用法

用法一:直接在 pandas 上跑 SQL。DuckDB 能挂载已有的 DataFrame 对象,不用把数据搬来搬去:

import duckdb
import pandas as pd

con = duckdb.connect()
df = pd.read_csv('orders.csv')

con.register('orders', df)
res = con.sql("""
    SELECT province, category, count(*) AS cnt,
           round(avg(amount), 2) AS avg_amount
    FROM orders
    WHERE order_date >= DATE '2026-01-01'
    GROUP BY 1, 2
    ORDER BY cnt DESC
""").df()

用法二:直接查 Parquet 目录。数据团队把日志按天写成 Parquet,DuckDB 可以用通配符一次性扫完,而且只读需要的列:

SELECT count(*), avg(duration)
FROM read_parquet('logs/*/*.parquet')
WHERE path LIKE '/api/%';

用法三:跨源联邦查询。同一条 SQL 里可以把本地 CSV、Postgres 表和 Parquet 文件 join 起来——联合分析场景里这个能力太省事了。

什么时候它跑得飞快,什么时候会翻车

快的情况:单机内存装得下(或稍大一点,DuckDB 会溢写到磁盘)、查询是聚合与扫描、数据是 Parquet/CSV 这类列格式。

容易翻车的情况:

和 ClickHouse、pandas 怎么选

场景推荐
单机一次性分析、几百 MB 到几十 GBDuckDB
多用户并发的实时分析服务ClickHouse
数据小而需要复杂 Python 生态操作pandas
嵌入式场景、随应用分发DuckDB(同 SQLite 定位)

我的实际用法是:探索阶段全用 DuckDB,脚本一跑就出结果;定型的定时报表如果数据量增长到百 GB,再迁到 ClickHouse。这个迁移路径很顺,SQL 写法基本兼容。

常见问题

DuckDB 能替代 MySQL 做业务数据库吗?

不能。DuckDB 面向分析型负载,同一时刻只允许一个写进程,没有完善的用户权限与事务隔离机制,不适合高并发小事务。业务库请继续用 MySQL/Postgres。

为什么它比 pandas 快?

pandas 是行式内存结构,聚合时要逐行处理且受 GIL 限制;DuckDB 用列式存储、向量化执行与多线程并行,只读需要的列,还能下推到 Parquet 的元数据跳过无关数据块。

数据量超过内存怎么办?

设置 SET memory_limit 与 SET temp_directory,DuckDB 会把中间结果溢写到磁盘,牺牲部分性能换取可处理更大的数据。也建议先把中间结果落成 Parquet,减少重复计算。