在Python中使用DuckDB进行本地SQL分析的快速入门指南

本文详细介绍了如何在Python中使用DuckDB这一嵌入式SQL OLAP引擎进行高效数据分析。内容包括安装配置、DataFrame查询、文件读取、性能对比及实际应用场景,帮助数据从业者快速上手这一轻量级分析工具。

在Python中使用DuckDB进行本地SQL分析

数据从业者如今寻求集速度、易用性和灵活性于一体的工具。DuckDB正是这样一个快速流行的工具。它是一个嵌入式SQL OLAP数据库,让你可以直接在Python环境中运行快速的分析查询。无论你是在Jupyter notebook中工作还是构建本地管道,DuckDB都能帮助你高效探索和分析数据,无需完整的数据库设置。

可以将DuckDB视为SQLite的分析表亲。SQLite专为事务性工作负载设计,而DuckDB则针对分析任务进行了优化。它直接读取Parquet和CSV文件,轻松与pandas集成,并以最小开销运行SQL。本教程将引导你开始使用DuckDB与Python。

第一步:安装DuckDB

开始使用DuckDB很简单。你可以使用pip安装它。无需配置服务器,也无需运行后台进程。像安装其他Python包一样安装它。

1
pip install duckdb

安装后,你可以导入并立即开始编写查询。DuckDB在进程中运行,这意味着你无需管理单独的数据库实例。这使其非常适合交互式数据分析和快速原型设计。

第二步:创建和查询DataFrame

让我们首先创建一个基本的pandas DataFrame。这将作为我们的样本数据集来测试DuckDB的SQL功能。

1
2
3
4
5
6
7
8
import duckdb
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'Diana'],
    'age': [25, 30, 35, 40],
    'salary': [70000, 80000, 90000, 100000]
})

DuckDB可以直接查询这个DataFrame。你无需将数据加载到单独的表中。你可以直接在其上编写SQL,就像它是一个表一样。

1
2
result = duckdb.query("SELECT name, salary FROM df WHERE age > 30").to_df()
print(result)

这种集成非常有用,特别是如果你更熟悉SQL而不是pandas语法。它还让你可以运行更复杂的查询,而无需手动编写循环或lambda函数。

第三步:使用SQL进行聚合和统计

DuckDB支持所有常见的SQL操作,包括分组、聚合和过滤。例如,你可以从同一个DataFrame中计算平均工资和最大年龄:

1
duckdb.query("SELECT AVG(salary) AS avg_salary, MAX(age) AS oldest FROM df").to_df()

这提供了一种清晰、声明性的方式来分析你的数据。你无需在pandas和SQL之间切换。你可以在SQL中完成大部分工作,这在团队工作中尤其有帮助,因为SQL是共享语言。

第四步:高效读取CSV和Parquet文件

DuckDB最令人印象深刻的功能之一是它可以直接从磁盘读取CSV和Parquet文件,而无需将整个数据集加载到内存中。这在处理大文件或希望在将数据加载到内存之前进行快速过滤时非常有用。

1
2
3
4
5
# 直接读取CSV文件
duckdb.query("SELECT * FROM 'employees.csv' WHERE department = 'Engineering'").to_df()

# 读取Parquet文件
duckdb.query("SELECT name, salary FROM 'employees.parquet' WHERE salary > 90000").to_df()

这些查询高效执行,并且只扫描文件的必要部分。这使得DuckDB在处理大型数据集时比pandas更有优势。

第五步:使用DuckDB作为持久化或内存数据库

DuckDB可以在内存模式和持久化模式下运行。如果你只是在实验或进行探索性工作,内存会话是完美的。如果你想保存表并在以后重用,可以使用基于文件的数据库。

1
2
3
4
5
6
7
# 内存会话
con = duckdb.connect()
con.register('people', df)
con.execute("SELECT COUNT(*) FROM people WHERE salary > 80000").fetchall()

# 持久化会话
con = duckdb.connect('my_duckdb_file.duckdb')

这种灵活性使DuckDB适用于快速实验以及可重复的脚本或管道。

第六步:在大型数据集上比较性能

为了演示DuckDB与pandas的比较,让我们在一百万行上运行一个基本的聚合操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import numpy as np
import time

large_df = pd.DataFrame({
    'id': np.random.randint(1, 10000, size=1_000_000),
    'value': np.random.rand(1_000_000)
})

# 使用pandas
start = time.time()
pandas_result = large_df.groupby(large_df['id'] % 10)['value'].sum()
print("Pandas time:", time.time() - start)

# 使用DuckDB
duckdb.register('large', large_df)
start = time.time()
duck_result = duckdb.query("SELECT id % 10 AS group_id, SUM(value) FROM large GROUP BY group_id").to_df()
print("DuckDB time:", time.time() - start)

在大多数测试中,DuckDB的性能比pandas更快,尤其是在聚合或连接大型数据集时。它还消耗更少的内存,因为它使用流式执行而不是一次性加载所有内容。

第七步:DuckDB的实际用例

DuckDB适用于各种工作流。分析师可以使用它在本地探索大型文件。数据工程师可以在ETL作业中使用它来过滤和转换数据。研究人员可以在Jupyter notebook中使用它运行可重复的查询。

一些实际例子包括:

  • 在不将大型Parquet数据集加载到内存的情况下生成摘要
  • 使用SQL组合多个CSV并过滤它们
  • 构建使用DuckDB实时查询数据的本地仪表板

你还可以将DuckDB与其他工具(如dbt、Polars或Apache Arrow)一起使用,使其成为现代数据工作流的强大选择。

总结

DuckDB是一个强大的工具,为你的Python项目带来了快速、进程内的SQL。它提供了SQL的易用性和原生引擎的性能,并完美地融入了涉及pandas、CSV和Parquet的现有工作流。

如果你正在寻找一种轻量级、现代的替代方案,用于本地分析的重型数据仓库解决方案,DuckDB值得一试。它开箱即用,在大型数据上表现良好,并以最小设置支持许多实际用例。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计