⌘+k ctrl+k
1.1.3 (stable)
Search Shortcut cmd + k | ctrl + k
Azure Extension

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

安装和加载

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

INSTALL azure;
LOAD azure;

使用

一旦认证设置完成,您可以按如下方式查询Azure存储:

Azure Blob Storage

允许的URI方案:azazure

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

Globs 也支持:

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

Globs 也支持:

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上,这可能会解决证书问题(错误:无效错误:无法获取新连接:https://⟨storage account name⟩.blob.core.windows.net/。SSL CA证书问题(路径?访问权限?)),因为指定扩展时,它会尝试在各种路径中查找捆绑证书(默认情况下,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。

使用密钥进行身份验证

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 自动获取的凭据链进行连接。 默认情况下,使用 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⟩'
);

可能的取值如下: cli; managed_identity; env; default;

如果没有提供显式的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 'http://localhost: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 请求。 STRING -
azure_account_name Azure 账户名称,设置后,扩展将尝试自动检测凭据(如果传递连接字符串则不使用)。 STRING -
azure_endpoint 在使用Azure凭证提供程序时覆盖Azure端点。 STRING blob.core.windows.net
azure_credential_chain Azure 凭证提供者的有序列表,以字符串格式分隔,使用 ; 分隔。例如:'cli;managed_identity;env'。请参阅 CREDENTIAL_CHAIN 提供者部分 中的可能值列表。如果传递连接字符串,则不使用此参数。 STRING -
azure_http_proxy 登录和执行对Azure的请求时使用的代理。 STRING HTTP_PROXY 环境变量(如果已设置)。
azure_proxy_user_name 如果需要,HTTP代理用户名。 STRING -
azure_proxy_password 如果需要,HTTP代理密码。 STRING -

附加信息

日志记录

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端点进行通配符匹配时,尤其是在使用(复杂的)通配符模式时,有一些重要的性能优势。

为了演示,我们来看一个例子,分别使用Glob和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

同时,通过数据湖端点执行的相同查询,

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端点将递归列出文件。特别是在分区/目录数量较多的情况下,性能差异可能非常显著。