DuckDB Python 入门指南:进程内的分析型数据库
DuckDB 是嵌入 Python 的高性能分析数据库,直接查询 CSV/Parquet/JSON 文件,列式存储 + 向量化执行。本文讲解安装、外部数据源查询、多源关联、持久化与 pandas 集成。
直接回答:DuckDB 是一个进程内分析型数据库——不用装服务器,pip install 之后直接在 Python 里跑 SQL,还能直接查询 CSV、Parquet、JSON 文件;列式存储与向量化执行面向扫描和聚合优化,但速度差距需要按相同数据和查询测试。
DuckDB 的定位
SQLite 统治了嵌入式事务处理,DuckDB 则瞄准嵌入式分析:聚合、窗口函数、大表扫描是它的主场。它不替代 PostgreSQL/MySQL(原生数据库文件的写入通常由单一进程管理,该进程内可并发事务),而是替代"把 CSV 导入数据库再分析"的繁琐流程——现在直接查文件。
安装上手
pip install duckdb
import duckdb
# 内存模式,即开即用
con = duckdb.connect()
con.sql("SELECT 42 AS answer").show()
直接查询外部文件
这是 DuckDB 的杀手特性——CSV/Parquet/JSON 即表:
# 直接查 CSV,无需导入
con.sql("SELECT * FROM 'sales.csv' LIMIT 5").show()
# Parquet 同理,还支持通配符批量
con.sql("SELECT region, SUM(amount) FROM 'data/2026/*.parquet' GROUP BY region").show()
类型自动推断, compressed 文件透明解压。Parquet 可裁剪列与过滤数据,实际可处理规模取决于内存、临时磁盘和查询算子。
探索性 SQL 全套可用
JOIN、窗口函数、CTE、透视(PIVOT)一应俱全:
con.sql("""
SELECT city,
SUM(amount) AS total,
RANK() OVER (ORDER BY SUM(amount) DESC) AS r
FROM 'orders.parquet'
GROUP BY city
ORDER BY total DESC
LIMIT 10
""").show()
多数据源关联
CSV 关联 Parquet 再关联远端表,一条 SQL 搞定:
con.sql("""
SELECT u.name, SUM(o.amount)
FROM 'users.csv' u
JOIN 'orders.parquet' o ON u.id = o.user_id
GROUP BY u.name
""").show()
还能接 PostgreSQL、SQLite、S3 上的文件——DuckDB 成了轻量的联邦查询引擎。
持久化
con = duckdb.connect("warehouse.duckdb") # 文件持久化
con.sql("CREATE TABLE analytics AS SELECT * FROM 'big.parquet'")
持久化数据库应在完成 checkpoint 并关闭写连接后复制;运行中不可仅复制主文件忽略 WAL。分析中间结果落库,下次直接查表。
与 pandas 协作
可与 pandas 交换数据,但 df() 等转换可能分配内存,不能一概视为零拷贝:
df = con.sql("SELECT * FROM 'sales.csv'").df() # 结果转 DataFrame
con.sql("SELECT AVG(total) FROM df").fetchone() # DataFrame 直接当表查
惯用流:DuckDB 负责重活(扫描、聚合、关联),pandas 负责精细加工与可视化。
常见问题(FAQ)
Q:DuckDB 和 SQLite 怎么选?
A:写入密集的事务型应用(嵌入式 KV、本地存储)选 SQLite;读密集的分析型查询选 DuckDB。两者都是单文件嵌入式,但执行引擎各为其主。
Q:能替代数据仓库吗?
A:适合本地和单机分析,是否替代仓库取决于并发、治理、容量和运维要求,不应按固定 GB/TB 阈值划线。
Q:内存不够会不会崩?
A:DuckDB 支持超出内存的外排序与溢出到磁盘,memory_limit 主要约束缓冲区管理器,并非进程总内存硬上限;并非所有算子都可溢写,仍可能出现内存不足。
官方参考
本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。