⌘+k ctrl+k
1.3 (稳定版)
搜索快捷键 cmd + k | ctrl + k
Azure 扩展

azure 扩展是一个可加载扩展,为 Azure Blob 存储 添加了文件系统抽象到 DuckDB。

安装和加载

azure 扩展将在首次使用时从官方扩展仓库透明地自动加载。如果您想手动安装和加载,请运行

INSTALL azure;
LOAD azure;

用法

一旦身份验证设置完毕,您可以如下查询 Azure 存储

Azure Blob 存储

允许的 URI 方案:azazure

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

也支持通配符

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';

也支持通配符

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_http_stats EXPLAIN ANALYZE 语句中包含来自 Azure 存储的 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: PEM 编码文件路径,包含发送到 libcurl 的证书颁发机构。请注意,此选项已知仅适用于 Linux,如果在其他平台设置可能会报错。
    • CURL_CA_PATH: 目录路径,包含 PEM 编码文件,包含发送到 libcurl 的证书颁发机构。

示例

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 扩展有多个秘密提供程序可用

  • 如果您需要为不同的存储账户定义不同的秘密,请使用 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_identityenvdefault

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

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 存储之间的区别

尽管 ADLS 实现了与 Blob 存储类似的功能,但对于通配符,特别是使用(复杂)通配符模式时,使用 ADLS 端点有一些重要的性能优势。

为了演示,我们来看一个通配符如何分别使用 Blob 和 ADLS 端点在内部执行的示例。

使用以下文件系统

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

同时,相同的查询可以通过数据湖端点执行,如下所示

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-10, root/l_receipmonth=1997-11, root/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=SHIP, root/l_receipmonth=1997-11/l_shipmode=SHIP, root/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 端点将递归列出文件。特别是在分区/目录数量较高时,性能差异可能非常显著。