azure
扩展是一个可加载的扩展,它为 DuckDB 添加了对 Azure Blob 存储 的文件系统抽象。
安装和加载
azure
扩展将在首次使用时从官方扩展仓库透明地 自动加载。
如果您想手动安装并加载它,请运行:
INSTALL azure;
LOAD azure;
使用
一旦认证设置完成,您可以按如下方式查询Azure存储:
Azure Blob Storage
允许的URI方案:az
或 azure
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中使用的底层适配器。有效值为:default 或 curl 。 |
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⟩'
);
默认的 PROVIDER
是 CONFIG
。
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_PROXY
、PROXY_USER_NAME
和PROXY_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端点将递归列出文件。特别是在分区/目录数量较多的情况下,性能差异可能非常显著。