DuckDB快速入门教程

DuckDB是一个用c++编写的进程内OLAP DBMS,太复杂了。我们从简单的开始,好吗?DuckDB是用于分析的SQLite。它没有依赖关系,非常容易设置,并且经过优化可以对数据执行查询。本文将介绍什么是DuckDB,如何使用它,以及为什么它对你很重要。

DuckDB应用场景

为什么DuckDB ?作为数据分析师或数据科学家,典型的工作流程是从CSV文件或S3桶加载数据,执行预处理步骤,然后运行分析。要实现这些功能,您需要打开一个Jupyter notebook,导入Numpy和Pandas,然后执行查询。有趣的是,如果回顾这些操作,通常包括类似数据库中的操作,如连接、聚合、筛选等。但是,不是使用关系数据库管理系统(RDBMS),而是使用Pandas和Numpy。

问题是,为什么?设置数据库并在其中,加载数据可能是一种痛苦、缓慢和令人沮丧的体验。如果这很容易,那么使用RDBMS就可以获得一切。这就是DuckDB要解决的需求场景,DuckDB是使用数据库分析数据的最简单和最快的方法。

DuckDB介绍

DuckDB优势

  • 本地化

​ 首先,DuckDB是进程内单文件数据库,没有外部依赖关系。这是什么意思?与Postgres不同,它不需要设置客户端/服务器,也不需要安装外部依赖项。此外,客户端与服务端之间的数据传输速度比正常情况下要慢。另一方面,DuckDB嵌入到主机应用程序进程中,并管理存储在单个文件中的数据库。没有客户机/服务器,安装起来很简单。如果你需要运行DB来进行本地数据分析,那么它就是你的选择!

  • 性能

​ 其次,DuckDB针对分析查询工作负载(OLAP)进行了高度优化。因为它是面向列的数据库(以及其他优化),所以聚合、连接或读取数据的复杂长时间查询变得非常快!可以很容易地说,90%的大数据工作负载可以在一台机器上处理,而不需要DuckDB进行任何设置或计算。Pandas不是这样的。Pandas不能利用CPU内核来并行计算,这使得它们完成起来很慢。它完全在内存中操作,如果数据集太大,就会导致内存不足错误。

  • SQL

​ 无论您喜欢与否,SQL比以往任何时候都更加活跃。DuckDB支持相当高级的SQL命令集,例如窗口函数和聚合。它提供事务性保证(ACID属性)并使用Postgres API。忘记丑陋和缓慢的pandas操作。你可以用优雅的SQL替换它们(它在SQL之上提供了一些附加功能,使其更友好,如下所示)。最后,DuckDB有一个Python客户端,当与Arrow和Parquet混合使用时,它会很出色。

​ 总之,DuckDB是开源的、可嵌入的、进程内的、面向列的SQL OLAP RDBMS。非常适合想要轻松快速地执行本地分析工作负载的数据从业者。

DuckDB限制

DuckDB被设计为在单台机器上运行。这意味着你的数据必须适合那台机器;否则,它不起作用。实际上,您可以使用功能强大的计算机来处理99%的工作负载。这应该不是问题,除非你每天处理数tb的数据。通过查看AWS产品,您可以拥有一个拥有1952gb内存和128个vcpu的实例。

另一个限制是DuckDB不是一个多租户数据库。拥有不同团队的不同人员、开发模型和共享数据库上的数据将是非常具有挑战性的。但是,当你将数据库与其他工具(如Airflow、S3、Parquet和dbt)集成时,可以获得一个健壮的数据生态系统,团队可以使用该生态系统高效地工作。

这本身并不是限制,但是DuckDB不是事务性数据库,不应该这样使用。

DuckDB vs SQLite

虽然SQLite是一个通用的数据库引擎,但它主要是为快速在线事务处理(OLTP)而设计的。

SQLite是:

  • 跨平台:SQLite数据库存储在单个文件中。
  • 紧凑和独立:可作为一个小文件。它不需要安装或配置,也没有外部依赖。
  • 可靠:经常用于关键任务应用程序,如飞行软件。
  • 快:每秒可以支持数万个事务。
  • ACID保证:事务是原子的、一致的、隔离的和持久的

上述特性与DuckDB相同。这就是为什么它声称是"用于分析的SQLite"。那么有什么不同呢?

DuckDB是为进程内OLAP从头开始构建的,采用列式存储、向量化查询处理和针对ETL操作优化的多版本并发控制。另一方面,SQLite使用面向行的存储格式,这意味着SQL查询对单个行而不是成批行进行操作,就像在向量化查询处理中那样,这会给OLAP查询带来较差的性能。

总之,他们都有许多共同的特点。但是,DuckDB针对跨大量行应用聚合计算的查询进行了优化,而SQLite针对单个数据行的快速扫描和查找进行了优化。如果您需要执行分析查询,请使用DuckDB;否则,使用SQLite。

Python操作DuckDB

是时候使用DuckDB了。首先,创建一个duckdb目录,以CSV数据文件为例,这里没有实际业务处理,实际内容不重要。下面数据集包含测试数据:销售数据,列为订单ID、产品、数量等。

Order_ID	Product	Quantity	Price	Order_Date
176558	USB-C Charging Cable	2	11.95	19-04-2019
176559	Bose SoundSport Headphones	1	99.99	07-04-2019
176560	Google Phone	1	600	12-04-2019
176560	Wired Headphones	1	11.99	12-04-2019
176561	Wired Headphones	1	11.99	30-04-2019
176562	USB-C Charging Cable	1	11.95	29-04-2019
176563	Bose SoundSport Headphones	1	99.99	02-04-2019
176564	USB-C Charging Cable	1	11.95	12-04-2019
176565	Macbook Pro Laptop	1	1,700.00	24-04-2019

要使用DuckDB,必须安装Python包。为了避免与机器上已经安装的包冲突,最好的做法是创建一个Python虚拟环境。为此,打开终端并键入命令python3 -m venv venv。通过执行source venv/bin/activate来激活环境,并在VS Code(或任何IDE)中运行一个单元。

在文件中输入# %%,创建VS Code类型的单元格,可以实现类似Notebook功能:

按shift+enter组合键,可以运行单元格内代码。

安装依赖

准备好Python虚拟环境后,创建一个新文件requirements.txt。该文件包含DuckDB工作所需的Python包以及DuckDB本身。

rust 复制代码
duckdb==1.1.3
pandas==2.1.1
seaborn==0.13.0
matplotlib==3.8.0

保存该文件并运行命令pip install -r requirements.txt来安装依赖项。

回到笔记本并在第一个单元格中添加以下导入:

创建数据库

默认情况下,不带参数的connect会创建一个全局存储在Python模块中的内存数据库。如果关闭启动连接的程序,就会丢失数据库和数据。如果希望持久化数据,则传递文件名进行连接,以便它创建与数据库对应的文件。

python 复制代码
conn = duckdb.connect()
# conn = duckdb.connect("my_db.db")

最后,如果你想查询现有的数据库,而不向它写入数据,传递read_only参数,如下所示:

python 复制代码
conn = duckdb.connect("my_db.db", read_only=True)

现在,采用第一个选项,创建内存数据库作为示例。

使用DuckDB查询数据

在新单元格中,增加并执行下面代码:

rust 复制代码
conn.sql("""
  SELECT *
  FROM 'data/*.csv'
  LIMIT 10
""")

SQL对数据库执行SQL查询。在上面的示例中,DuckDB加载数据集目录中的所有CSV文件并打印前10行。在底层,DuckDB使用CSVLoader自动推断列和类型。如你所见,这很简单。为CSV文件提供路径,就可以像查询SQL表一样查询它们。当然DuckDB支持很多文件类型,如Parquet、Hive分区、JSON等等。

能够查询数据固然很好,但是从查询中检索数据就更好了!DuckDB提供了多种方法,可以使用这些方法来有效地检索数据,例如:

  • fetchnumpy()将数据作为Numpy数组的字典
  • df()将数据作为Pandas数据框
  • arrow()将数据作为arrow表
  • pl()将数据作为polar数据框

最终根据需求选择合适的方法。作为最佳实践,不要使用fetch_one或fetch_all,因为它们会为查询返回的每个值创建一个Python对象。如果有很多数据,可能会出现内存错误或性能问题。

让我们通过像这样更改前面的单元格来检索数据作为Pandas Dataframe:

python 复制代码
# %%
conn = duckdb.connect("my_db.db")
df = conn.sql("""
  SELECT *
  FROM 'data/*.csv'
  LIMIT 10
""").df()
df

执行结果如下:

从Dataframe创建表

现在,你已经使用DuckDB直接查询了这些文件。另一种方法是将前一个查询的输出注册为一个虚拟表,这样你就可以使用通常的SQL表特性查询数据。如何?简单!

python 复制代码
# %%
conn.register("df_view", df)
print(conn.execute("DESCRIBE df_view").df())

print(conn.execute("DESCRIBE df_view").df())

这将从数据帧df创建虚拟表df_view。重新运行单元将得到预期的输出:

总结

DuckDB通过易于使用和高效地查询任何数据来节省您的时间。不需要通过经典的RDBMS来加载和查询数据,只需使用DuckDB即可。对于大多数场景,可能不需要100个cpu和100Gb内存的大型设置。此外,DuckDB还提供了与Pandas、Arrow、Polars、Parquet和Numpy等许多知名包的兼容性,这使得在它们之间进行操作变得方便。希望大家喜欢,下次教程再见!

相关推荐
梦想画家9 小时前
DuckDB: 从MySql导出数据至Parquet文件
数据工程·duckdb·分析工程
梦想画家4 天前
Polars数据聚合与旋转实战教程
数据工程·分析工程
梦想画家1 个月前
dbt 数据分析工程实战教程(汇总篇)
数据治理·数据工程·分析工程
梦想画家2 个月前
理解dbt artifacts及其实际应用
数据治理·数据转换·1024程序员节·数据工程·分析工程
梦想画家2 个月前
Dbt增量策略模型实践指南
大数据·数据治理·数据工程·分析工程
梦想画家3 个月前
DBT hook 实战教程
数据治理·数据工程·分析工程
叶庭云3 个月前
数据异质性与数据异构性的本质和举例说明
人工智能·数据科学·数据异构性·数据工程·数据异质性
梦想画家3 个月前
dbt compile 命令及应用
数据仓库·数据转换·分析工程
梦想画家3 个月前
dbt seed 命令及应用示例
数据转换·数据工程·分析工程