⌘+k ctrl+k
1.4 (LTS)
搜索快捷键 cmd + k | ctrl + k
Azure 扩展

azure 扩展是一个可加载的扩展,它为 DuckDB 增加了对 Azure Blob Storage 的文件系统抽象,从而支持数据的读取和写入。

安装和加载

azure 扩展在首次使用时会从官方扩展仓库中透明地自动加载。如果您希望手动安装并加载它,请运行

INSTALL azure;
LOAD azure;

用法

一旦设置好身份验证,您就可以按照以下方式查询 Azure 存储

Azure Blob 存储

允许的 URI 方案:azazure

SELECT count(*)
FROM 'az://my_container/path/my_file.parquet_or_csv';

同时也支持使用 Glob 模式

SELECT *
FROM 'az://my_container/path/*.csv';
SELECT *
FROM 'az://my_container/path/**';

或者使用完全限定路径语法

SELECT count(*)
FROM 'az://my_storage_account.blob.core.windows.net/my_container/path/my_file.parquet_or_csv';
SELECT *
FROM 'az://my_storage_account.blob.core.windows.net/my_container/path/*.csv';

Azure Data Lake Storage (ADLS)

允许的 URI 方案:abfss

SELECT count(*)
FROM 'abfss://my_filesystem/path/my_file.parquet_or_csv';

同时也支持使用 Glob 模式

SELECT *
FROM 'abfss://my_filesystem/path/*.csv';
SELECT *
FROM 'abfss://my_filesystem/path/**';

或者使用完全限定路径语法

SELECT count(*)
FROM 'abfss://my_storage_account.dfs.core.windows.net/my_filesystem/path/my_file.parquet_or_csv';
SELECT *
FROM 'abfss://my_storage_account.dfs.core.windows.net/my_filesystem/path/*.csv';

写入 Azure Blob Storage

您可以使用 COPY 语句将数据直接写入 Azure Blob 或 ADLSv2 存储。

-- Write query results to a Parquet file on Blob Storage
COPY (SELECT * FROM my_table)
TO 'az://my_container/path/output.parquet';
-- Write a table to a CSV file on ADLSv2 Storage
COPY my_table
TO 'abfss://my_container/path/output.csv';

您也可以使用完全限定路径

COPY my_table
TO 'az://my_storage_account.blob.core.windows.net/my_container/path/output.parquet';

配置

使用以下配置选项来控制扩展读取远程文件的方式

名称 描述 类型 默认值
azure_http_stats EXPLAIN ANALYZE 语句中包含来自 Azure Storage 的 HTTP 信息。 BOOLEAN false
azure_read_transfer_concurrency Azure 客户端可用于单次并行读取的最大线程数。如果 azure_read_transfer_chunk_size 小于 azure_read_buffer_size,则将此值设置为 > 1 将允许 Azure 客户端执行并发请求以填充缓冲区。 BIGINT 5
azure_read_transfer_chunk_size Azure 客户端在单次请求中读取的最大字节数。建议将其设置为 azure_read_buffer_size 的约数。 BIGINT 1024*1024
azure_read_buffer_size 读取缓冲区的大小。建议将其设置为 azure_read_transfer_chunk_size 的整数倍。 UBIGINT 1024*1024
azure_transport_option_type Azure SDK 中使用的底层适配器。有效值为:defaultcurl VARCHAR 默认值 (default)
azure_context_caching 在执行查询时,启用/禁用 DuckDB 连接上下文中底层 Azure SDK HTTP 连接的缓存。如果您怀疑这导致了某些副作用,可以尝试将其设置为 false 来禁用它(不推荐)。 BOOLEAN true

azure_transport_option_type 显式设置为 curl 会产生以下效果

  • 在 Linux 上,这可能解决证书问题(Error: Invalid Error: Fail to get a new connection for: https://storage_account_name.blob.core.windows.net/. Problem with the SSL CA cert (path? access rights?)),因为指定该选项后,扩展会尝试在不同路径中查找捆绑证书(这是 curl 默认不会做的,且由于静态链接可能会出错)。
  • 在 Windows 上,这会替换默认适配器(WinHTTP),从而允许您使用所有 curl 功能(例如使用 socks 代理)。
  • 在所有操作系统上,它都将遵循以下环境变量
    • CURL_CA_INFO:包含发送给 libcurl 的证书颁发机构的 PEM 编码文件的路径。请注意,已知此选项仅在 Linux 上有效,在其他平台上设置可能会报错。
    • CURL_CA_PATH:包含发送给 libcurl 的证书颁发机构的 PEM 编码文件所在的目录路径。

示例

SET azure_http_stats = false;
SET azure_read_transfer_concurrency = 5;
SET azure_read_transfer_chunk_size = 1_048_576;
SET azure_read_buffer_size = 1_048_576;

身份验证

Azure 扩展有两种配置身份验证的方式。推荐的方式是使用 Secrets。

使用 Secret 进行身份验证

Azure 扩展提供了多种密钥提供程序 (Secret Providers)

  • 如果您需要为不同的存储账户定义不同的密钥,请使用 SCOPE 配置。请注意,SCOPE 要求结尾处带斜杠(SCOPE 'azure://some_container/')。
  • 如果您使用完全限定路径,则 ACCOUNT_NAME 属性是可选的。

CONFIG 提供程序

默认提供程序 CONFIG(即用户配置)允许使用连接字符串或匿名方式访问存储账户。例如

CREATE SECRET secret1 (
    TYPE azure,
    CONNECTION_STRING 'value'
);

如果您不使用身份验证,仍然需要指定存储账户名称。例如

CREATE SECRET secret2 (
    TYPE azure,
    PROVIDER config,
    ACCOUNT_NAME 'storage_account_name'
);

默认的 PROVIDERCONFIG

credential_chain 提供者

credential_chain 提供程序允许使用 Azure SDK 通过 Azure 凭据链自动获取的凭据进行连接。默认情况下,使用 DefaultAzureCredential 链,它会按照 Azure 文档中指定的顺序尝试凭据。例如

CREATE SECRET secret3 (
    TYPE azure,
    PROVIDER credential_chain,
    ACCOUNT_NAME 'storage_account_name'
);

DuckDB 还允许使用 CHAIN 关键字指定特定的链。这接受一个分号分隔的提供程序列表(a;b;c),系统将按顺序尝试这些提供程序。例如

CREATE SECRET secret4 (
    TYPE azure,
    PROVIDER credential_chain,
    CHAIN 'cli;env',
    ACCOUNT_NAME 'storage_account_name'
);

可能的值如下:climanaged_identityworkload_identityenvdefault

如果未提供明确的 CHAIN,则默认值为 default

托管身份 (Managed Identity)

可以通过 credential_chain 优雅且自动地使用托管身份 (MI)。在通常情况下,如果执行环境只有一个可用的 MI,则无需任何配置。

如果您的执行环境有多个身份,请使用 MANAGED_IDENTITY 提供程序并指定要使用的身份。此提供程序允许通过 CLIENT_IDOBJECT_IDRESOURCE_ID 其中之一来指定身份,例如

CREATE SECRET secret1 (
    TYPE AZURE,
    PROVIDER MANAGED_IDENTITY,
    ACCOUNT_NAME 'storage account name',
    CLIENT_ID 'used-assigned managed identity client id'
);

该提供程序可以在不指定 ID 的情况下使用;如果只有一个 ID 可用,此提供程序的功能将与 credential_chain 提供程序相同,并使用该单一可用 ID。如果存在多个 ID,则行为是未定义的(或者更具体地说,由 Azure SDK 定义)——因此我们建议在这种情况下明确设置身份。

SERVICE_PRINCIPAL 提供程序

SERVICE_PRINCIPAL 提供程序允许使用 Azure 服务主体 (SPN) 进行连接。

可以使用密钥

CREATE SECRET azure_spn (
    TYPE azure,
    PROVIDER service_principal,
    TENANT_ID 'tenant_id',
    CLIENT_ID 'client_id',
    CLIENT_SECRET 'client_secret',
    ACCOUNT_NAME 'storage_account_name'
);

或者使用证书

CREATE SECRET azure_spn_cert (
    TYPE azure,
    PROVIDER service_principal,
    TENANT_ID 'tenant_id',
    CLIENT_ID 'client_id',
    CLIENT_CERTIFICATE_PATH 'client_cert_path',
    ACCOUNT_NAME 'storage_account_name'
);

配置代理

在使用密钥时要配置代理信息,您可以在密钥定义中添加 HTTP_PROXYPROXY_USER_NAMEPROXY_PASSWORD。例如

CREATE SECRET secret5 (
    TYPE azure,
    CONNECTION_STRING 'value',
    HTTP_PROXY 'https://:3128',
    PROXY_USER_NAME 'john',
    PROXY_PASSWORD 'doe'
);
  • 当使用密钥时,HTTP_PROXY 环境变量仍将被遵循,除非您为它提供了明确的值。
  • 当使用密钥时,使用变量进行身份验证会话中的 SET 变量将被忽略。
  • 对于 Azure credential_chain 提供程序,实际的令牌是在查询时获取的,而不是在创建密钥时。

使用变量进行身份验证(已弃用)

SET variable_name = variable_value;

其中 variable_name 可以是以下之一

名称 描述 类型 默认值
azure_storage_connection_string Azure 连接字符串,用于验证和配置 Azure 请求。 字符串 -
azure_account_name Azure 账户名称,设置后,扩展将尝试自动检测凭据(如果您传递了连接字符串,则不使用此项)。 字符串 -
azure_endpoint 在使用 Azure 凭据提供程序时覆盖 Azure 终端节点。 字符串 blob.core.windows.net
azure_credential_chain Azure 凭据提供程序的有序列表,以字符串格式用 ; 分隔。例如:'cli;managed_identity;env'。请参阅 credential_chain 提供程序部分中可能的值列表。如果您传递了连接字符串,则不使用此项。 字符串 -
azure_http_proxy 登录及向 Azure 发送请求时使用的代理。 字符串 HTTP_PROXY 环境变量(如果已设置)。
azure_proxy_user_name 如果需要,HTTP 代理用户名。 字符串 -
azure_proxy_password 如果需要,HTTP 代理密码。 字符串 -

附加信息

日志记录

Azure 扩展依赖 Azure SDK 连接到 Azure Blob 存储,并支持将 SDK 日志打印到控制台。要控制日志级别,请设置 AZURE_LOG_LEVEL 环境变量。

例如,可以在 Python 中启用详细日志,如下所示

import os
import duckdb

os.environ["AZURE_LOG_LEVEL"] = "verbose"

duckdb.sql("CREATE SECRET myaccount (TYPE azure, PROVIDER credential_chain, SCOPE 'az://myaccount.blob.core.windows.net/')")
duckdb.sql("SELECT count(*) FROM 'az://myaccount.blob.core.windows.net/path/to/blob.parquet'")

ADLS 与 Blob Storage 的区别

尽管 ADLS 实现了与 Blob 存储类似的功能,但在使用 Glob 模式(尤其是复杂的 Glob 模式)时,使用 ADLS 终端节点具有一些显著的性能优势。

为了演示,我们来看一个分别使用 Blob 和 ADLS 终端节点在内部执行 Glob 操作的示例。

使用以下文件系统

root
├── l_receipmonth=1997-10
│   ├── l_shipmode=AIR
│   │   └── data_0.csv
│   ├── l_shipmode=SHIP
│   │   └── data_0.csv
│   └── l_shipmode=TRUCK
│       └── data_0.csv
├── l_receipmonth=1997-11
│   ├── l_shipmode=AIR
│   │   └── data_0.csv
│   ├── l_shipmode=SHIP
│   │   └── data_0.csv
│   └── l_shipmode=TRUCK
│       └── data_0.csv
└── l_receipmonth=1997-12
    ├── l_shipmode=AIR
    │   └── data_0.csv
    ├── l_shipmode=SHIP
    │   └── data_0.csv
    └── l_shipmode=TRUCK
        └── data_0.csv

以下查询通过 Blob 终端节点执行

SELECT count(*)
FROM 'az://root/l_receipmonth=1997-*/l_shipmode=SHIP/*.csv';

它将执行以下步骤

  • 列出所有以 root/l_receipmonth=1997- 为前缀的文件
    • root/l_receipmonth=1997-10/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-10/l_shipmode=AIR/data_0.csv
    • root/l_receipmonth=1997-10/l_shipmode=TRUCK/data_0.csv
    • root/l_receipmonth=1997-11/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-11/l_shipmode=AIR/data_0.csv
    • root/l_receipmonth=1997-11/l_shipmode=TRUCK/data_0.csv
    • root/l_receipmonth=1997-12/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-12/l_shipmode=AIR/data_0.csv
    • root/l_receipmonth=1997-12/l_shipmode=TRUCK/data_0.csv
  • 使用请求的模式 root/l_receipmonth=1997-*/l_shipmode=SHIP/*.csv 过滤结果
    • root/l_receipmonth=1997-10/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-11/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-12/l_shipmode=SHIP/data_0.csv

同时,相同的查询可以通过 datalake 终端节点执行,如下所示

SELECT count(*)
FROM 'abfss://root/l_receipmonth=1997-*/l_shipmode=SHIP/*.csv';

这将执行以下步骤

  • 列出 root/ 中的所有目录
    • root/l_receipmonth=1997-10
    • root/l_receipmonth=1997-11
    • root/l_receipmonth=1997-12
  • 过滤并列出子目录:root/l_receipmonth=1997-10root/l_receipmonth=1997-11root/l_receipmonth=1997-12
    • root/l_receipmonth=1997-10/l_shipmode=SHIP
    • root/l_receipmonth=1997-10/l_shipmode=AIR
    • root/l_receipmonth=1997-10/l_shipmode=TRUCK
    • root/l_receipmonth=1997-11/l_shipmode=SHIP
    • root/l_receipmonth=1997-11/l_shipmode=AIR
    • root/l_receipmonth=1997-11/l_shipmode=TRUCK
    • root/l_receipmonth=1997-12/l_shipmode=SHIP
    • root/l_receipmonth=1997-12/l_shipmode=AIR
    • root/l_receipmonth=1997-12/l_shipmode=TRUCK
  • 过滤并列出子目录:root/l_receipmonth=1997-10/l_shipmode=SHIProot/l_receipmonth=1997-11/l_shipmode=SHIProot/l_receipmonth=1997-12/l_shipmode=SHIP
    • root/l_receipmonth=1997-10/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-11/l_shipmode=SHIP/data_0.csv
    • root/l_receipmonth=1997-12/l_shipmode=SHIP/data_0.csv

正如您所见,由于 Blob 终端节点不支持目录的概念,过滤只能在列出文件之后进行,而 ADLS 终端节点可以递归地列出文件。特别是在分区/目录数量较多的情况下,性能差异可能会非常显著。

© 2025 DuckDB 基金会,阿姆斯特丹,荷兰
行为准则 商标使用指南