DuckDB 嵌入式 OLAP 分析

FreeGuideOnline 最新 2026-07-14

DuckDB 简介

DuckDB 是一款开源、高性能的嵌入式联机分析处理(OLAP)数据库管理系统。它以“进程内”方式运行,无需独立服务器,可直接嵌入应用程序,为分析型查询提供类似 SQLite 的零配置体验。DuckDB 支持标准 SQL,能够高效处理大型数据集,特别适合数据科学、本地分析和边缘计算场景。

它的核心特点包括:

  • 嵌入式架构:DuckDB 作为动态链接库运行在宿主进程中,没有守护进程或网络协议开销。
  • 列式存储引擎:采用向量化执行和压缩列存,针对聚合、过滤等 OLAP 操作深度优化。
  • 完整 SQL 支持:兼容 PostgreSQL 风格 SQL,包括窗口函数、CTE、复杂类型(数组、结构体)。
  • 多数据源集成:直接查询 CSV、Parquet、JSON、MySQL、PostgreSQL、SQLite 等外部文件或数据库。
  • 极简部署:单文件可执行程序,或通过 Python/R/Node.js/Java 等语言的包管理器安装。

前置知识要求

学习本教程前,您无需预先掌握任何数据库知识。具备基础 SQL 概念(如 SELECT、WHERE、GROUP BY)会有帮助,但教程将从零开始讲解。我们会使用 Python 作为主要交互语言,因此需要您已安装 Python 3.8 以上版本。

环境搭建

安装 DuckDB

DuckDB 提供多种安装方式。最常用的是通过 Python 包管理器安装 duckdb 模块。

pip install duckdb

安装完成后,您就可以在 Python 脚本或交互环境中导入使用。其他语言用户可参考官方文档安装对应客户端。

命令行工具

DuckDB 也提供独立的命令行界面(CLI),可直接下载二进制文件启动交互式查询。在终端输入以下命令进入 DuckDB Shell:

duckdb

您将看到 DuckDB 的提示符,可以立即执行 SQL 语句。

第一个 DuckDB 数据库

DuckDB 数据库可以完全存在于内存中,也可以持久化到磁盘文件。创建持久化数据库只需在连接时指定文件路径。

内存数据库

import duckdb

# 创建内存数据库连接(程序结束时数据消失)
con = duckdb.connect()

持久化数据库

con = duckdb.connect('my_database.db')
# 如果文件不存在,DuckDB 会自动创建

执行查询后,数据将自动保存。DuckDB 的 .db 文件是单个文件,可以轻松复制和共享。

创建表与加载数据

DuckDB 支持从多种来源直接创建表。我们将从创建内存表开始,然后演示如何从 CSV 和 Parquet 文件导入。

手动创建表

con.execute("""
CREATE TABLE sales (
    id INTEGER,
    product TEXT,
    quantity INTEGER,
    price DOUBLE,
    sale_date DATE
);
""")

使用 SQL INSERT 插入数据:

con.execute("""
INSERT INTO sales VALUES
    (1, 'Laptop', 2, 1200.0, '2025-01-10'),
    (2, 'Mouse', 5, 25.0, '2025-01-11'),
    (3, 'Keyboard', 3, 75.0, '2025-01-11');
""")

直接查询外部文件

无需导入,直接用 read_csv_auto 函数查询 CSV 文件:

con.execute("""
SELECT * FROM read_csv_auto('sales_data.csv')
""").fetchall()

read_csv_auto 会自动推断列类型和分隔符。对于 Parquet 文件,使用 read_parquet

一次性创建表并加载数据

con.execute("""
CREATE TABLE sales AS 
SELECT * FROM read_csv_auto('sales_data.csv')
""")

DuckDB 会将 CSV 数据物化到本地表,后续查询速度会更快。您也可以直接查询外部文件而不创建表,DuckDB 的智能缓存机制能减少重复扫描。

基础分析查询

以下示例演示 DuckDB 在 OLAP 场景下的典型用法。

聚合与分组

计算每种产品的销售总额和平均数量:

SELECT 
    product,
    SUM(quantity * price) AS total_revenue,
    AVG(quantity) AS avg_qty
FROM sales
GROUP BY product;

窗口函数

为每个销售记录添加累计销售额:

SELECT 
    sale_date,
    product,
    price,
    SUM(price) OVER (ORDER BY sale_date) AS running_total
FROM sales;

复杂子查询与 CTE

查找销售额超过平均销售额的产品:

WITH product_revenue AS (
    SELECT product, SUM(quantity * price) AS revenue
    FROM sales
    GROUP BY product
)
SELECT * FROM product_revenue 
WHERE revenue > (SELECT AVG(revenue) FROM product_revenue);

嵌入式分析特性

与 Pandas DataFrame 无缝互操作

DuckDB 的核心优势在于与 Python 数据科学生态深度集成。可以直接在 DataFrame 上执行 SQL,无需复制数据。

import pandas as pd

df = pd.read_csv('sales_data.csv')
# 将 DataFrame 注册为 DuckDB 表
con.register('sales_df', df)
result = con.execute("SELECT product, SUM(quantity) FROM sales_df GROUP BY product").df()
print(result)

结果直接以 DataFrame 返回。您也可以在 SQL 查询中直接使用 DataFrame 对象,例如:con.sql("SELECT * FROM df")

查询 Pandas/Arrow 表

从 DuckDB 0.7 版本开始,支持对 Pandas 和 Arrow 表进行零拷贝查询。使用 con.sql 方法:

# 直接对 DataFrame 查询
result_df = con.sql("SELECT product, AVG(price) FROM df GROUP BY product").df()

这种机制避免了序列化开销,适合交互式分析。

直接访问 Parquet 数据集

大规模数据通常以 Parquet 格式存储。DuckDB 可以高效查询整个 Parquet 文件目录:

con.execute("""
SELECT station, AVG(temperature) 
FROM read_parquet('weather/*.parquet')
WHERE year = 2024
GROUP BY station
""")

DuckDB 会读取列统计信息和谓词下推,只扫描相关列和行组,性能远超 Pandas。

使用 DuckDB 进行数据探索

分析 CSV 文件

假设我们有一个 2GB 的销售 CSV 文件,不需要完整加载到内存即可分析。

# 直接查询 CSV,使用自动类型推断
con.execute("DESCRIBE SELECT * FROM read_csv_auto('big_sales.csv')").df()

DESCRIBE 查看表结构。然后执行聚合查询,DuckDB 会在向量化引擎下快速完成。

连接多个数据源

DuckDB 可以在一个查询中跨不同文件类型执行 JOIN。

SELECT 
    c.name, 
    SUM(o.amount) 
FROM read_csv_auto('customers.csv') c
JOIN read_parquet('orders.parquet') o ON c.id = o.customer_id
GROUP BY c.name;

无需设置外部服务器,DuckDB 把不同文件视作虚拟表。

性能优化建议

  1. 使用持久化表:重复查询的数据应加载到持久化表中,利用列存压缩和内存缓存。
  2. 选择合适文件格式:Parquet 比 CSV 查询效率高得多,因为支持列裁剪和谓词下推。
  3. 限制结果集大小:在分析时使用 LIMIT 抽样,确认查询逻辑后再做全量计算。
  4. 利用向量化函数:DuckDB 内置了大量优化过的函数,避免在 SQL 中使用复杂的 Python UDF。
  5. 调整内存和并行度:通过 SET threads TO 4;SET memory_limit='4GB'; 控制资源使用。

DuckDB 与 SQLite 的区别

虽然两者都是嵌入式数据库,但设计目标不同:

特性 DuckDB SQLite
工作负载 分析(OLAP),读密集型 事务(OLTP),写密集型
存储结构 列式,高压缩 行式,面向记录
查询性能 聚合查询极快 点查极快,聚合较慢
SQL 特性 丰富分析函数,窗口,复杂类型 标准 SQL,功能精简
数据来源 直接读取外部文件,无导入 需导入数据才能查询
并发 单个写入者,多读取者(MVCC) 单个写入者,多读取者

通常,在数据分析脚本、Jupyter Notebook 或数据管道中使用 DuckDB;在移动应用、网站后端等需要频繁事务的场景使用 SQLite。

总结

DuckDB 重新定义了嵌入式分析数据库:它以零成本安装、完整 SQL 支持、极速列式引擎,让分析师和数据工程师能够在本地高效处理 GB 甚至 TB 级数据。通过本教程,您已学会:

  • 安装 DuckDB 并创建数据库。
  • 从 CSV/Parquet 等文件直接查询数据。
  • 使用 SQL 进行聚合、窗口计算和数据探索。
  • 与 Pandas 深度集成,实现嵌入式分析。
  • 基本性能优化方法。

接下来,您可以尝试将 DuckDB 应用到实际项目中,例如构建本地数据仪表板、ETL 管道中的数据转换步骤,或作为交互式探索工具替代沉重的分布式系统。DuckDB 的轻量和强大将显著提升您的分析效率。