一、为什么要关注 DuckDB?

在数据分析的日常工作中,我们常常需要处理 CSV、Parquet 等格式的文件,用 Pandas 做数据探索,或者快速搭建一个轻量的分析环境。但问题也随之而来:

  • Pandas 虽然灵活,但在处理大规模数据时显得吃力;
  • 传统数据库(如 PostgreSQL、MySQL)需要独立安装、维护服务,部署复杂;
  • 一些内存计算工具虽快,但缺少完整 SQL 支持,难以扩展。

这时,DuckDB 作为“数据界的 SQLite”走进了越来越多开发者的视野。它不需要单独的服务进程,可以直接嵌入到 Python、R 或者应用程序中使用;同时支持 SQL 的完整能力,还能高效读取和写入常见文件格式。对于个人开发者和数据分析师来说,它既轻量又强大,几乎是随取随用的分析利器。

接下来,我们就从基础概念到实际操作,一步步了解 DuckDB。

二、DuckDB简介

DuckDB 是一个轻量级的嵌入式分析型数据库,它最大的特点是无外部依赖。无论在编译还是运行时,DuckDB 都不需要额外的组件支持。官方发布版本甚至只由一个头文件和一个实现文件组成,这种“合并文件”的设计让它在部署和集成上极为简洁。

与传统数据库需要独立的服务进程不同,DuckDB 是直接嵌入在主程序中的。这样的架构使得数据在程序与数据库之间的传输更高效,在分析型场景下尤其具有优势。比如在 Python 中,DuckDB 可以直接对 Pandas DataFrame 执行查询,而无需额外导入或复制数据。

DuckDB 还具备极强的跨平台能力,支持 Linux、macOS、Windows 等主流系统,也兼容 x86 和 ARM 架构。无论是轻量的边缘设备,还是拥有数百 CPU 核心的大型服务器,都能顺畅运行。甚至通过 DuckDB-Wasm,它还能在浏览器和移动端中直接执行。

在功能层面,DuckDB 完全支持 SQL 的复杂查询,包括丰富的函数库和窗口函数,并通过定制化的 MVCC(多版本并发控制)保证 ACID 特性。它不仅可以存储为持久化的单文件数据库,还支持二级索引以加快查询。由于内置了列式存储和矢量化执行引擎,DuckDB 在 OLAP(分析型处理)场景中往往比传统的 PostgreSQL、MySQL 等行式数据库拥有更高的效率。

此外,DuckDB 提供了灵活的扩展机制,用户可以自定义新的数据类型、文件格式或函数。目前对 Parquet、JSON、HTTP(S)、S3 等特性的支持,正是通过扩展实现的。这意味着 DuckDB 的生态在不断扩展和演进。

三、简单使用

DuckDB 的使用门槛非常低。只需下载对应的可执行文件 DuckDB Installation – DuckDB,直接打开 duckdb.exe 即可进入命令行界面。在提示符下输入 SQL 语句,就能像操作传统数据库一样执行查询。例如

最后显示的D是提示符,表示在DuckDB中,此时输入SQL,回车即可执行,比如使用 show databases;

DuckDB 的 SQL 语法整体上与 PostgreSQL 相似,而 CLI 工具则借鉴了 SQLite 的命令行体验。因此,即使是第一次接触,也几乎没有学习成本。

四、内存数据库与持久数据库

在实际应用中,DuckDB 提供了两种常见的使用方式:内存数据库持久数据库

4.1区别

  • 内存数据库:数据完全保存在内存中,速度极快,适合做临时分析和中间步骤计算。但一旦进程关闭,数据随之消失。
  • 持久数据库:数据存储在磁盘文件(.duckdb)中,可以长期保存和复用。虽然涉及磁盘 IO,速度略低于内存模式,但由于 DuckDB 的列存和向量化优化,性能依旧很优秀。

简单来说,如果你只是临时处理数据,用内存库即可;而当需要保存结果或多次复用时,就该选择持久库。

4.2 案例

内存数据库

在命令行直接输入 duckdb,不指定文件路径,默认就是内存数据库:

duckdb

进入交互式界面后,你可以看到提示符:

v0.10.2 d65efb20d
Enter ".help" for usage hints.
D

此时数据库只存在于内存中。例如:

CREATE TABLE users(id INTEGER, name VARCHAR);
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');

SELECT * FROM users;

结果会显示:

1  Alice
2  Bob

一旦退出 \qCTRL+D,内存数据库会销毁,数据不再存在。

持久数据库

如果要创建一个持久化数据库(磁盘文件),需要在启动 CLI 时指定文件名:

./duckdb mydb.duckdb

这会在当前目录下生成一个名为 mydb.duckdb 的文件。你在里面创建的表和数据都会保存到这个文件里。

示例:

CREATE TABLE products(id INTEGER, name VARCHAR);
INSERT INTO products VALUES (100, 'iPhone'), (200, 'ThinkPad');

SELECT * FROM products;

退出后,再重新进入:

./duckdb mydb.duckdb

继续执行:

SELECT * FROM products;

你会发现数据还在。

五、DuckDB Python API

DuckDB 需要 Python 3.9 或更高版本。

DuckDB 的 Python API 可以通过 pip 安装: pip install duckdb

5.1 数据读取

DuckDB 可以从多种格式中导入数据——包括磁盘和内存中的数据。

  • 读取CSV文件
import duckdb

data_csv = duckdb.read_csv("data.csv")
results = duckdb.sql("select * from data_csv where datasource_id = 10")
print(results.fetchall())
  • 读取Pandas
import pandas as pd

# 1. 构造一个 Pandas DataFrame,模拟数据源
data = {
    "id": [1, 2, 3, 4],
    "name": ["Alice", "Bob", "Charlie", "Diana"],
    "age": [25, 30, 35, 40],
    "city": ["Tokyo", "London", "New York", "Beijing"]
}
df = pd.DataFrame(data)

print("=== 原始 Pandas DataFrame ===")
print(df)

results = duckdb.sql("select * from df where id = 1")
print(results.fetchall())
  • DuckDB数据源

    DuckDB整体支持的数据源如下表

数据格式/方式 函数示例 说明
CSV/TSV/文本 read_csv_auto('file.csv') 自动推断格式/类型
Parquet read_parquet('file.parquet') 支持分区/目录
JSON/JSONL read_json_auto('file.json') 自动推断 schema
Excel read_excel('file.xlsx') 可选 sheet
ORC read_orc('file.orc') 兼容 Hadoop 生态
Avro read_avro('file.avro') 常见大数据序列化格式
Arrow 直接 SELECT * FROM arrow_table 与 Pandas 互操作
Pandas DataFrame 直接 SELECT * FROM df 无需转换
HTTP(S) read_csv_auto('https://...') 可直接读网络文件
S3/GCS/Azure read_parquet('s3://...') 需 httpfs 插件

5.2 数据落盘

DuckDB 支持将 Relation 对象直接以多种格式写入磁盘。

results = duckdb.sql("select * from df where id = 1")
results.write_csv("output.csv")

总结来说,DuckDB支持下面格式的数据落盘

方式 格式 示例
文件导出 CSV write_csv("out.csv")
Parquet write_parquet("out.parquet")
JSON/JSONL write_json("out.json")
Excel (xlsx) write_excel("out.xlsx")
ORC COPY ... TO 'out.orc' (FORMAT ORC)
Avro COPY ... TO 'out.avro' (FORMAT AVRO)
Python 对象 Pandas .fetchdf()
Numpy .fetchnumpy()
Arrow .arrow()
Python list .fetchall()
数据库文件 DuckDB file duckdb.connect('mydb.duckdb')
云存储 S3/GCS/Azure COPY ... TO 's3://...' (FORMAT PARQUET)

5.3 内存与持久化数据

在 Python 中,既可以创建 :memory: 数据库(纯内存模式),也可以指定磁盘文件实现持久化。内存模式关闭连接后数据会消失,而持久化数据库则能在下次连接时继续使用。

这种灵活性使得 DuckDB 既能胜任临时的数据探索,又能作为轻量级 OLAP 数据仓库长期保存数据。参见下面的案例,展示DuckDB的内存与持久化数据在Python中的使用案例。

import duckdb
import pandas as pd

# 构造一个 Pandas DataFrame,模拟数据源
df = pd.DataFrame({
    "id": [1, 2, 3],
    "name": ["Alice", "Bob", "Charlie"],
    "age": [25, 30, 35]
})

print("=== 原始 Pandas DataFrame ===")
print(df)

# ============================
# 1. 内存数据库(:memory:)
# ============================
con_mem = duckdb.connect(database=':memory:')  # 内存数据库
con_mem.register("people", df)  # 注册 DataFrame 作为表

print("\n=== 内存数据库查询(age > 28)===")
print(con_mem.execute("SELECT * FROM people WHERE age > 28").fetchdf())

# 关闭连接(数据会消失)
con_mem.close()

# 再次连接内存数据库,表就不存在了
con_mem = duckdb.connect(database=':memory:')
try:
    con_mem.execute("SELECT * FROM people")
except Exception as e:
    print("\n[内存库验证] 再次连接时查询 people 报错:", e)
con_mem.close()

# ============================
# 2. 持久化数据库(mydb.duckdb)
# ============================
con_disk = duckdb.connect(database='mydb.duckdb', read_only=False)  # 持久化文件

# 创建表并插入数据
con_disk.execute("CREATE TABLE IF NOT EXISTS people (id INTEGER, name VARCHAR, age INTEGER)")
con_disk.execute("INSERT INTO people VALUES (1, 'Alice', 25), (2, 'Bob', 30), (3, 'Charlie', 35)")

print("\n=== 持久化数据库查询(age > 28)===")
print(con_disk.execute("SELECT * FROM people WHERE age > 28").fetchdf())

con_disk.close()

# 再次连接持久化数据库,表依旧存在
con_disk = duckdb.connect(database='mydb.duckdb')
print("\n[持久化验证] 再次连接时 people 表依然存在:")
print(con_disk.execute("SELECT * FROM people").fetchdf())
con_disk.close()

六、总结

DuckDB 的定位非常清晰:一个面向分析的嵌入式数据库。它兼顾了轻量和高效的特性,既能作为临时工具快速处理数据,又能作为轻量级 OLAP 数据库长期保存分析结果。
在实践中,你会发现 DuckDB 带来的便利主要体现在三个方面:

  1. 无需复杂部署:开箱即用,像操作 SQLite 一样简单;
  2. 强大的数据兼容性:能直接对 CSV、Parquet、Pandas 等多种数据源执行 SQL;
  3. 高性能执行引擎:基于列存与矢量化,适合分析型查询。

如果你是一名数据分析师、数据工程师,或者正在寻找一种简单又高效的数据处理方案,DuckDB 值得你尝试。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐