DeepSeek总结的DuckLake 入门
来源https://motherduck.com/第 2 章 DuckLake 入门如第 1 章所述启动并运行 DuckLake 既快速又简单。然而除了初始设置之外还有几个架构决策需要考虑使用哪个后端数据库来托管目录数据将存储在哪里以及哪个计算引擎将运行您的工作负载。主要优势在于这些决策不必在第一天就最终确定。您可以从一个使用 DuckDB 管理目录和本地存储的本地 DuckLake 实例开始然后随着时间的推移逐步演进例如将目录迁移到 PostgreSQL并将数据存储在 S3 等云对象存储中。本章将探讨主要的 DuckLake 部署模式并概述每种模式的权衡。它还将提供实际示例演示如何随着需求的变化来实现这些配置。此外我们将介绍 DuckLake 的云和 SaaS 选项以及如何加载数据和执行基本的 CRUD 操作。到本章结束时您将能够轻松地设置本地 DuckLake 环境和基于云的部署。对于本书后续的所有示例以及那些在我们 GitHub 仓库中跟随操作的示例在 DuckDB 中执行 SQL 脚本就像下面这个命令一样简单duckdb-c.read the_file.sql对于涉及更复杂逻辑如循环或特殊环境变量的脚本我们将使用 Python 3.11 和 UV 作为默认执行模式。对于这些脚本您可以像下面这样简单地运行它们uv run the_script.py在选择部署方法之前了解可用 DuckLake 目录选项之间的权衡是很有帮助的。表 2-1 总结了最常见的设置并强调了每种选项在何时可能适用。表 2-1. 部署选项比较目录类型优点缺点附加说明用户托管 DuckDB• 极其容易设置• 无需外部数据库• 非常适合实验• 并发能力有限• 不理想的多用户环境非常适合开始使用 DuckLake、进行本地开发和小型单用户工作负载用户托管 Postgres• 支持多个并发用户• 来自云提供商的成熟可靠性和高可用选项• 需要管理数据库服务• 额外的运维开销对于团队需要共享 DuckLake 目录的生产部署的常见选择MotherDuck• 最小的运维开销• 按需无服务器计算• 高性能缓存• 可以自带 S3 存储桶进行存储• 商业服务• 对底层基础设施的控制较少适合偏好托管平台的易用性和性能的团队本地 DuckLake 部署让我们继续为本教程安装 DuckDB CLI 并启动它。根据您的工作站类型以下是一些不错的安装选项•Mac: 使用 Homebrew -brew install duckdb•Linux: 使用 curl -curl https://install.duckdb.org | sh•Windows: 从 DuckDB 网站下载或使用 Winget 包管理器安装好 DuckDB 后启动 CLI 并安装 DuckLakeduckdb install ducklake;对于那些更喜欢 DuckDB 图形界面的人来说您只需在 duckdb 命令中添加--ui标志它就会弹出一个 Web 用户界面供您编写查询。以下是启动 DuckDB GUI 的示例duckdb--ui现在我们已运行 DuckDB 并安装了 DuckLake 扩展我们可以按如下方式创建一个简单的本地 DuckLakeATTACHORREPLACEducklake:local_inst.ducklakeasmy_ducklake(DATA_PATH concat(getenv(HOME),/dw1));让我们分解一下ducklake:local_inst.ducklake as my_ducklake的实际含义•ducklake:告诉 DuckDB 您想要创建一个 DuckLake 目录•local_inst.ducklake告诉 DuckDB DuckLake 目录数据库的名称。您可以将其命名为其他名称例如my_local_instance.db为了清楚说明它作为数据库的类型我们认为ducklake后缀在这里最有意义。•my_ducklake实际上是您附加到 DuckDB 会话时 DuckLake 目录的别名当您想要在 DuckLake 目录中创建或更新对象如表时它很有帮助。•DATA_PATH告诉 DuckLake 目录所有表的数据将存储在哪里。这里您会注意到当我们指定数据路径时我们使用了 DuckDB CLI 函数getenv该函数可以获取环境变量例如用户的 home 路径。您会注意到当您运行上述命令时您会在启动 DuckDB CLI 的文件夹中看到local_inst.ducklake文件。这就是您的 DuckLake 目录。从这里开始我们可以执行一些简单的操作例如使用以下命令创建一个表CREATETABLEmy_ducklake.ordersASSELECT1asorder_id,DATE2024-01-01ASorder_date,100.0ASamountUNIONALLSELECT2,DATE2024-03-04,150;现在我们已经设置了一个本地 DuckLake 目录让我们介绍一些更实用的操作例如导入数据和执行基本的创建、读取、更新、删除CRUD操作。导入数据将数据导入 DuckLake 目录非常简单鉴于 DuckLake 是 DuckDB 的扩展您可以访问所有 DuckDB 函数例如读取 CSV 和 Parquet 文件。在下一个示例中我们将使用以下 Python 脚本构建一个简单的 CSV 文件withopen(customer_orders.csv,w)asf:f.write(order_id,order_date,customer_id 1001,2026-03-01,C001 1002,2026-03-02,C002 1003,2026-03-03,C003 )或者如果您希望完全使用 DuckDB CLI我们可以按如下方式构建相同的 CSV 文件COPY(FROM(VALUES(1001,2026-03-01,C001),(1002,2026-03-02,C002),(1003,2026-03-03,C003))AScustomer_orders(order_id,order_date,customer_id))TOcustomer_orders.csv;现在我们有了文件可以使用以下命令将 CSV 导入到我们的本地 DuckLake 目录CREATEORREPLACETABLEmy_ducklake.cust_ordersASSELECT*FROMcustomer_orders.csv;-- 查看数据SELECT*FROMmy_ducklake.cust_orders;如果您不熟悉所有 DuckDB 的数据导入函数我们鼓励您查阅此处的文档。DuckDB 支持读取 CSV、Parquet、JSON 以及许多其他数据源和文件格式。导入命令提供了广泛灵活性即使是一些更生僻的文件格式也能轻松摄取。CRUD 操作DuckLake 支持所有 DuckDB CRUD 操作• CTAS• INSERT• UPDATE• DELETE• MERGE让我们来看每种语句类型的示例。CTAS 语句CTAS 代表 “CREATE TABLE AS SELECT …”。该语句将表的创建和数据的插入合并到单个操作中。CTAS 不是发出一个 CREATE TABLE 语句后跟一个 INSERT INTO 语句而是允许在一个简洁的命令中执行这两个步骤这简化了许多数据工程工作流。下面是一个 CTAS 语句的示例。它创建了一个名为cust_orders的表如果表已存在则执行替换CREATEORREPLACETABLEmy_ducklake.cust_ordersASSELECT1001ASorder_id,DATE2024-01-01ASorder_date,C001AScustomer_idUNIONALLSELECT1002,DATE2024-01-02,C002;注意使用CREATE OR REPLACE TABLE AS。这通过自动替换表的任何现有版本进一步扩展了 CTAS 模式。在实践中这意味着您可以通过一个语句从查询中重建表无需先显式删除先前的表。INSERT 语句下面是一个 INSERT INTO 语句的示例它将一条新记录追加到cust_orders表INSERTINTOmy_ducklake.cust_ordersVALUES(1004,2024-01-04,C004);UPDATE 语句以下示例对cust_orders表中的一条现有记录执行了 UPDATE 操作UPDATEmy_ducklake.cust_ordersSETorder_date2024-01-05WHEREorder_id1004;DELETE 语句您也可以在 DuckLake 中执行 DELETE 语句。下面的示例从cust_orders表中删除了一条记录DELETEFROMmy_ducklake.cust_ordersWHEREorder_id1003;MERGE 语句为了演示 MERGE 语句我们将首先创建表的一个修改版本称为tmp_orders其中order_date向前移动了一天。这将模拟我们将用于 MERGE 到目标表的暂存数据CREATEORREPLACETABLEmy_ducklake.tmp_ordersASSELECTorder_id,date_add(order_date,INTERVAL1 day)ASorder_date,customer_idFROMmy_ducklake.cust_orders;创建好这个暂存表后执行 MERGE 就很简单了MERGEINTOmy_ducklake.cust_ordersAStargetUSINGmy_ducklake.tmp_ordersASsourceONtarget.order_idsource.order_idWHENMATCHEDTHENUPDATEWHENNOTMATCHEDTHENINSERTBYNAME;关于 DuckDB 对 MERGE 的实现有几点值得注意。该语句包含了几项便利性——我们之前称之为语法糖。例如在WHEN MATCHED子句中您可以显式列出要更新的列。但是如果您省略它们DuckDB 将自动更新源表和目标表之间名称匹配的列。类似地在WHEN NOT MATCHED子句中INSERT BY NAME关键字告诉 DuckDB 通过对齐两个表中相同名称的列来插入值。如果需要您仍然可以显式列出要插入的列但BY NAME提供了一个更简单且通常更具可读性的选项。这些便利性使得常见的 MERGE 操作变得简洁同时在需要更显式行为时仍然允许完全控制。本地 Postgres 目录现在我们已经介绍了在 DuckDB 数据库中创建本地 DuckLake 目录让我们继续使用本地 PostgreSQL 实例来执行此操作。您可以从官方网站下载 Postgres。如果您使用的是 Mac我们建议您使用 brew services 按如下方式安装 Postgresbrewinstallpostgresql安装完成后我们将在其默认的 postgres 数据库下启动 Postgres并按如下方式创建/建一个名为ducklake_v1的新数据库。您会注意到我们使用 brew 来启动 Postgres 实例。brew services start postgresql16 psql-dpostgres-cDROP DATABASE IF EXISTS ducklake_v1;psql-dpostgres-cCREATE DATABASE ducklake_v1;请注意在上述语句中我们删除并重新创建数据库如果不存在以保持本教程的可重复性。对于生产工作负载您必须非常小心不要随意运行 drop database 命令。此时我们已经启动并运行了一个本地 Postgres 实例其中包含我们全新的ducklake_v1数据库并且我们准备使用以下命令将实际的 DuckLake 目录附加到 Postgres并使用本地数据存储ATTACHducklake:postgres:dbnameducklake_v1 hostlocalhostASwh(DATA_PATH concat(getenv(HOME),/dwpg1));从这里开始您现在可以执行上一节中介绍的所有表 CRUD 操作。云对象存储的数据路径到目前为止示例中使用的都是本地存储来存放 DuckLake 数据文件。然而DuckLake 同样可以轻松地将其数据存储在云对象存储如 Amazon S3中只需在附加目录时在DATA_PATH参数中指定所需位置即可。例如CREATEORREPLACESECRET aws_creds(TYPES3,provider credential_chain);ATTACHORREPLACEducklake:postgres:dbnameducklake_v1 hostlocalhostASwh(DATA_PATH concat(s3://,getenv(AWS_BUCKET),/ducklake_pg),OVERRIDE_DATA_PATHTrue);在此示例中DATA_PATH参数指示 DuckLake 将表数据存储在 S3 存储桶中而不是本地文件系统。重要提示数据路径覆盖当首次附加 DuckLake 目录并指定了DATA_PATH时该位置成为与该目录关联的默认数据路径。后续的ATTACH操作将继续使用此默认位置除非您明确提供不同的路径。OVERRIDE_DATA_PATH参数允许您为当前连接临时覆盖此默认路径。但重要的是要理解此覆盖是会话范围的并不会永久更改目录已配置的数据路径。此外覆盖数据路径不会迁移任何已写入原始位置的数据。表将继续引用在先前路径下创建的数据文件。因此我们强烈建议不要为单个表混合使用多个数据路径。这会创建一个难以管理和排查的复杂场景。如果您需要将现有的 DuckLake 部署迁移到新的存储位置则必须执行显式迁移。迁移策略将在后面的章节中讨论。MotherDuck 托管的 DuckLake另一种部署选项是使用 MotherDuck 的托管 DuckLake 服务。MotherDuck 是一个无服务器云数据仓库由 DuckDB 计算引擎提供支持。由于 MotherDuck 是无服务器的因此没有需要您管理的基础设施。这意味着您可以连接到一个计算实例其 RAM 范围从几 GB 到超过 1TB并且该实例将在短短 200 毫秒内创建完成。每个连接都可以获得自己独立的 compute Duckling因此就像 DuckLake 使计算民主化一样不存在可能过载的中心化计算集群。您也不必放弃本地开发的体验。当您通过 DuckDB 客户端连接到 MotherDuck 时您可以使用该本地计算环境通过 Dual Execution 运行查询。或者您可以完全使用 DuckDB 进行本地开发然后在生产环境中重新运行最终确定的查询而无需更改代码——SQL 保持不变。连接到 MotherDuck有几种方法可以连接到 MotherDuck。最简单的方法是访问 https://app.motherduck.com 并登录 Web UI。它看起来就像 DuckDB UI。如果您以前没有使用过 MotherDuck您将被自动重定向到入门流程。您可以开始免费试用或使用免费套餐。完成后您将直接登录到您的帐户并准备好开始查询。另一种选择是使用 DuckDB 客户端并指向特殊的数据库名称md:。这适用于任何客户端但例如要使用 CLI 内置的本地 DuckDB UI 进行连接请运行duckdb md:-ui就是这样。系统会提示您登录或注册然后就可以开始了。要通过编程方式连接到 MotherDuck 而无需基于浏览器的身份验证流程请使用访问令牌。通过 UI 登录 MotherDuck 后单击左上角的“设置”按钮然后在左侧窗格中选择“访问令牌”。或者您可以在基于浏览器的 UI 版本中直接访问 http://app.motherduck.com/settings/tokens。获得该令牌后将其设置为环境变量motherduck_token。CLI 将自动检测该令牌的存在对于其他库可以在连接字符串中传递它。例如要使用 Python 连接请使用 DuckDB 库但编辑连接字符串# /// script# dependencies [duckdb,]# ///importduckdbfromosimportgetenv tokengetenv(motherduck_token)conduckdb.connect(fmd:?motherduck_token{token})连接到 MotherDuck Postgres 端点连接到 MotherDuck 的另一个选项是使用 Postgres 端点。MotherDuck 可以支持 Postgres 有线协议因此任何 Postgres 驱动程序都可以像与 Postgres 通信一样与 MotherDuck 通信。在任何您使用 Postgres 的现有工作流中您都可以使用 MotherDuck DuckLake。使用以下命令通过psql连接将region替换为您的 MotherDuck AWS 区域例如us-east-1PGPASSWORD$MOTHERDUCK_TOKENpsql\-hpg.region-aws.motherduck.com\-p5432\-Upostgres\dbnamesample_data sslmodeverify-full sslrootcertsystem当使用另一个 Postgres 驱动程序时可以使用 libpq URI 作为连接字符串。此示例使用 Python 的 psycopg Postgres 驱动程序进行连接。# /// script# dependencies [psycopg,]# ///importosimportpsycopg tokenos.environ[motherduck_token]regionus-east-1-aws.motherduck.comconn_strfpostgresql://postgres:{token}pg.{region}:5432/md:?sslmodeverify-fullsslrootcertsystemwithpsycopg.connect(conn_str)asconn:withconn.cursor()ascur:cur.execute( SELECT title, score FROM sample_data.hn.hacker_news WHERE type story ORDER BY score DESC LIMIT 5 )print(cur.fetchall())在 MotherDuck 上的 DuckLakeMotherDuck 提供了几种部署 DuckLake 的选项。操作最简单的是完全托管的 DuckLake。MotherDuck 将提供目录、对象存储和计算资源。完全托管的 DuckLake 具有一些独特的好处例如自动文件维护和用于提高读取性能的额外缓存。创建一个完全托管的 DuckLake 就像连接到 MotherDuck 并运行这段 SQL 片段一样简单CREATEDATABASEmy_ducklake(TYPEDUCKLAKE);请注意MotherDuck 上的完全托管 DuckLake 使用的是CREATE DATABASE语法而不是ATTACH。如果您更愿意将数据存储在自己的账户中可以创建一个自带存储桶的 DuckLake。只需提供对象存储桶的凭据然后在创建 DuckLake 时指定该存储桶的名称即可。CREATEORREPLACESECRET my_secretINMOTHERDUCK(types3,region getenv(AWS_REGION),key_id getenv(AWS_ACCESS_KEY_ID),secret getenv(AWS_SECRET_ACCESS_KEY),scope getenv(AWS_BUCKET));CREATEDATABASEmy_ducklake(TYPEDUCKLAKE,DATA_PATHs3://bucket-name/);第三个选项是创建一个自带计算的 DuckLake其中 MotherDuck 将管理目录而您提供存储桶和计算环境。要使用此选项请存储对象存储凭据在 MotherDuck 上创建 DuckLake然后将 MotherDuck 元数据目录附加到您想要运行计算的位置。首先在直接连接到 MotherDuck 时运行以下查询。CREATEORREPLACESECRET my_secretINMOTHERDUCK(types3,region getenv(AWS_REGION),key_id getenv(AWS_ACCESS_KEY_ID),secret getenv(AWS_SECRET_ACCESS_KEY),scope getenv(AWS_BUCKET));CREATEDATABASEmy_ducklake(TYPEDUCKLAKE,DATA_PATHs3://bucket-name/);然后在您想要运行计算的位置运行以下命令ATTACHducklake:md:__ducklake_metadata_database_nameASdatabase_alias;当您自带计算时再次使用了ATTACH语法。总之在 MotherDuck 上操作 DuckLake 的选项有托管选项目录存储计算使用场景完全托管 DuckLakeMotherDuckMotherDuckMotherDuck您想要一个简单的无服务器选项自带存储桶 DuckLakeMotherDuck自托管MotherDuck您希望拥有自己的数据自带计算 DuckLakeMotherDuck自托管自托管您想要使用多个计算引擎