你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

Azure Database for PostgreSQL 中 Azure 存储扩展的快速入门示例

下面是一系列示例,可帮助你了解如何使用 Azure 存储扩展。

创建 Azure 存储帐户并使用数据填充它

  1. 创建 Azure 存储帐户。 若要创建 Azure 存储帐户,如果还没有帐户,请自定义值 <resource_group><location><account_name>以及 <container_name>运行以下 Azure CLI 命令:
    random_suffix=$(tr -dc 'a-z0-9' </dev/urandom | head -c8)
    resource_group="resource-group-$random_suffix"
    location="eastus2"
    storage_account="storageaccount$random_suffix"
    blob_container="container-$random_suffix"
    az group create --name $resource_group --location $location
    az storage account create --resource-group $resource_group --name $storage_account --location $location --sku Standard_LRS --kind BlobStorage --public-network-access enabled --access-tier hot
    echo "Take note of the storage account name, which you'll have to replace in subsequent examples, whenever you find a reference to <account_name>:"
    echo $storage_account
    echo "Take note of the container name, which you'll have to replace in subsequent examples, whenever you find a reference to <container_name>:"
    echo $blob_container
    
  2. 创建 Blob 容器。 若要创建 Blob 容器,请运行以下 Azure CLI:
    az storage container create --account-name $storage_account --name $blob_container -o tsv
    
  3. 提取分配给存储帐户的两个访问密钥之一。 请确保复制access_key的值,因为需要在后续步骤中将其作为参数传递给 azure_storage.account_add 。 若要提取两个访问密钥中的第一个,请运行以下 Azure CLI 命令:
    access_key=$(az storage account keys list --resource-group $resource_group --account-name $storage_account --query [0].value)
    echo "Following is the value of your access key:"
    echo $access_key
    
  4. 下载包含示例期间使用的数据集的文件,并将其上传到 Blob 容器。 若要使用数据集下载文件,请运行以下 Azure CLI 命令:
    mkdir --parents azure_storage_examples
    cd azure_storage_examples
    curl -L -O https://github.com/Azure-Samples/azure-postgresql-storage-extension/raw/main/storage_extension_sample.parquet
    az storage blob upload-batch --account-name $storage_account --destination $blob_container --source . --pattern "storage_extension_sample.parquet" --account-key $access_key --overwrite --output none --only-show-errors
    curl -L -O https://github.com/Azure-Samples/azure-postgresql-storage-extension/raw/main/parquet_without_extension
    az storage blob upload-batch --account-name $storage_account --destination $blob_container --source . --pattern "parquet_without_extension" --account-key $access_key --overwrite --output none --only-show-errors
    curl -L -O https://github.com/Azure-Samples/azure-postgresql-storage-extension/raw/main/storage_extension_sample.csv
    az storage blob upload-batch --account-name $storage_account --destination $blob_container --source . --pattern "storage_extension_sample.csv" --account-key $access_key --overwrite --output none --only-show-errors
    curl -L -O https://github.com/Azure-Samples/azure-postgresql-storage-extension/raw/main/csv_without_extension
    az storage blob upload-batch --account-name $storage_account --destination $blob_container --source . --pattern "csv_without_extension" --account-key $access_key --overwrite --output none --only-show-errors
    

注释

可以列出特定存储帐户中存储的容器或 blob,但前提是 PostgreSQL 用户或角色通过使用 azure_storage.account_user_add 授予对该存储帐户的引用的权限。 角色的成员 azure_storage_admin 通过 azure_storage.account_add 添加的所有 Azure 存储帐户授予此权限。 默认情况下,仅向角色授予成员azure_pg_adminazure_storage_admin

创建在其中加载数据的表

让我们创建一个表,将上传到存储帐户的文件的内容导入其中。 为此,请使用 PostgreSQL for Visual Studio Code(预览版)psqlPgAdmin 或客户端连接到 Azure Database for PostgreSQL 灵活服务器的实例,并执行以下语句:

CREATE TABLE IF NOT EXISTS sample_data (
    id BIGINT PRIMARY KEY,
    sample_text TEXT,
    sample_integer INTEGER,
    sample_timestamp TIMESTAMP
);

准备扩展以供使用

在继续之前,请确保:

  1. 加载扩展库
  2. 允许列表扩展
  3. 创建扩展

添加存储帐户的访问密钥

此示例演示如何添加对存储帐户的引用,以及该存储帐户的访问密钥,该存储帐户需要通过 Azure Database for PostgreSQL 灵活服务器实例中扩展提供 azure_storage 的功能访问其内容。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

同样, <access_key> 必须设置为从存储帐户中提取的值。

SELECT azure_storage.account_add('<account_name>', '<access_key>');

小窍门

如果要从 Azure 门户检索存储帐户名称和其中一个访问密钥,请在资源菜单中选择“访问密钥”,复制存储帐户名称,然后从 key1 部分复制密钥(必须先选择“显示密钥”旁)。

授予对 Azure Blob 存储参考上的用户或角色的访问权限

此示例演示如何授予对命名 <regular_user>用户或角色的访问权限,以便此类 PostgreSQL 用户可以使用 azure_storage 扩展来访问托管在引用的 Azure 存储帐户托管的容器中的 Blob。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<regular_user> 必须设置为现有用户或角色的名称。

SELECT * FROM azure_storage.account_user_add('<account_name>', '<regular_user>');

列出容器中的所有 Blob

此示例演示如何列出存储帐户<container_name>容器<account_name>中的所有现有 Blob。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

SELECT * FROM azure_storage.blob_list('<account_name>','<container_name>');

列出具有特定名称前缀的 Blob

此示例演示如何列出存储帐户<container_name>容器<account_name>内的所有现有 blob,其 blob 名称以<blob_name_prefix>其开头。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

<blob_name_prefix> 应设置为要枚举 Blob 的任何前缀,以包含在其名称中。 如果要返回所有 Blob,可以将此参数设置为空字符串,甚至不指定此参数的值,在这种情况下,该值默认为空字符串。

SELECT * FROM azure_storage.blob_list('<account_name>','<container_name>','<blob_name_prefix>');

或者,可以使用以下语法:

SELECT * FROM azure_storage.blob_list('<account_name>','<container_name>') WHERE path LIKE '<blob_name_prefix>%';

使用 COPY FROM 语句导入数据

以下示例演示如何通过storage_extension_sample.parquet命令从位于 Azure 存储帐户<container_name>中的 Blob 容器<account_name>中的 blob COPY 导入数据:

  1. 创建与源文件架构匹配的表:

    CREATE TABLE IF NOT EXISTS sample_data (
        id BIGINT PRIMARY KEY,
        sample_text TEXT,
        sample_integer INTEGER,
        sample_timestamp TIMESTAMP
    );
    
  2. COPY使用语句将数据复制到目标表中。 格式从文件的扩展名推断为 Parquet。

    TRUNCATE TABLE sample_data;
    COPY sample_data
    FROM 'https://<account_name>.blob.core.windows.net/<container_name>/storage_extension_sample.parquet';
    
  3. COPY使用语句将数据复制到目标表中。 由于无法从文件扩展名推断编码格式,因此它通过 FORMAT 选项显式指定。

    TRUNCATE TABLE sample_data;
    COPY sample_data
    FROM 'https://<account_name>.blob.core.windows.net/<container_name>/parquet_without_extension'
    WITH (FORMAT 'parquet');
    
  4. COPY使用语句将数据复制到目标表中。 可以从文件扩展名推断编码格式。 但是,需要通过 HEADERS 选项显式配置第一行中的列标题。

    TRUNCATE TABLE sample_data;
    COPY sample_data
    FROM 'https://<account_name>.blob.core.windows.net/<container_name>/storage_extension_sample.csv'
    WITH (HEADERS);
    
  5. 执行以下 SELECT 语句以确认数据已加载到表中。

    SELECT *
    FROM sample_data
    LIMIT 100;
    

使用 COPY TO 语句导出数据

以下示例演示如何通过COPY命令将数据从名为sample_data表的数据导出到具有不同名称的多个 Blob,以及其编码格式等特征,所有这些 Blob 都驻留在 Azure 存储帐户<account_name>中的 Blob 容器<container_name>中:

  1. 创建与源文件架构匹配的表:

    CREATE TABLE IF NOT EXISTS sample_data (
        id BIGINT PRIMARY KEY,
        sample_text TEXT,
        sample_integer INTEGER,
        sample_timestamp TIMESTAMP
    );
    
  2. 将数据加载到表中。 运行 INSERT 语句以使用多个合成行填充它,或使用 COPY FROM 语句示例的导入数据 来填充示例数据集的内容。

  3. COPY使用语句将数据从目标表复制出来。 指定编码格式必须为 parquet。

    COPY sample_data
    TO 'https://<account_name>.blob.core.windows.net/<container_name>/storage_extension_sample_exported.parquet'
    WITH (FORMAT 'parquet');
    
  4. COPY使用语句将数据从目标表复制出来。 指定编码格式必须是 CSV,生成的文件的第一行包含列标题。

    COPY sample_data
    TO 'https://<account_name>.blob.core.windows.net/<container_name>/storage_extension_sample_exported.csv'
    WITH (FORMAT 'csv', HEADERS);
    
  5. 执行以下 SELECT 语句以确认 Blob 存在于存储帐户中。

    SELECT * FROM azure_storage.blob_list('<account_name>','<container_name>') WHERE path LIKE 'storage_extension_sample_exported%';
    

从 Blob 读取内容

blob_get函数在存储的引用容器<container_name><account_name>中检索一个特定 Blob 的内容。 为了 blob_get 了解如何分析可在窗体 NULL::table_name中传递值的数据,其中 table_name 引用的表的架构与所读取的 Blob 的架构匹配。 在此示例中,它指的是 sample_data 我们在开始时创建的表。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

<blob_name> 应设置为要读取其内容的 Blob 的完整路径。

在这种情况下,必须使用分析 blob 的解码器从文件扩展名推断。.parquet

SELECT * FROM azure_storage.blob_get
        ('<account_name>'
        ,'<container_name>'
        ,'storage_extension_sample.parquet'
        , NULL::sample_data)
LIMIT 5;

或者,可以使用AS函数之后的子句显式定义结果的架构。

SELECT * FROM azure_storage.blob_get('<account_name>','<container_name>','storage_extension_sample.parquet')
AS res (
        id BIGINT PRIMARY KEY,
        sample_text TEXT,
        sample_integer INTEGER,
        sample_timestamp TIMESTAMP)
LIMIT 5;

读取、筛选和修改从 Blob 读取的内容

此示例演示了在将 Blob 导入的内容加载到 SQL 表中之前,可以筛选和修改导入的内容。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

SELECT concat('P-',id::text) FROM azure_storage.blob_get
        ('<account_name>'
        ,'<container_name>'
        ,'storage_extension_sample.parquet'
        , NULL::sample_data)
WHERE sample_integer=780
LIMIT 5;

使用自定义选项从文件中读取内容(标题、列分隔符、转义字符)

此示例演示如何通过将options_copyoptions的结果传递给参数来使用自定义分隔符和转义字符。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

SELECT * FROM azure_storage.blob_get
        ('<account_name>'
        ,'<container_name>'
        ,'storage_extension_sample.csv'
        ,NULL::sample_data
        ,options := azure_storage.options_csv_get(header := 'true')
        );

使用解码器选项

此示例演示了选项 decoder 的使用。 如果解码器选项不存在,则会从文件的扩展名推断出来。 但是,如果文件名没有扩展名,或者当该文件扩展名不对应于与解码器关联的扩展名时,必须使用解码器来正确分析文件的内容,则可以显式传递解码器参数。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

SELECT * FROM azure_storage.blob_get
        ('<account_name>'
        ,'<container_name>'
        ,'parquet_without_extension'
        , NULL::sample_data
        , decoder := 'parquet')
LIMIT 5;

基于 Blob 内容计算聚合

此示例演示如何对存储在 Blob 容器中的信息执行聚合作,而无需将 Blob 的内容导入 PostgreSQL 表。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

SELECT sample_integer, COUNT(*) FROM azure_storage.blob_get
        ('<account_name>'
        ,'<container_name>'
        ,'storage_extension_sample.parquet'
        , NULL::sample_data)
GROUP BY sample_integer
ORDER BY 2 DESC
LIMIT 5;

将内容写入 Blob

blob_put函数构成一个特定 Blob 的内容(sample_data_copy.parquet在本例中),并将其上传到存储的<container_name>引用容器<account_name>。 此示例用于 blob_get 构造一组五行,然后传递给 blob_put 聚合函数,该函数将其作为名为 sample_data_copy.parquetblob 上传。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<container_name> 必须设置为 Blob 容器的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为blob_container环境变量的任何值匹配。

编码格式根据文件扩展名 .parquet推断为 parquet。

SELECT azure_storage.blob_put
        ('<account_name>'
        ,'<container_name>'
        ,'sample_data_copy.parquet'
        , top_5_sample_data)
FROM (SELECT * FROM sample_data LIMIT 5) AS top_5_sample_data;

编码格式根据文件扩展名 .csv推断为 CSV。

SELECT azure_storage.blob_put
        ('<account_name>'
        ,'<container_name>'
        ,'sample_data_copy.csv'
        , top_5_sample_data)
FROM (SELECT * FROM sample_data LIMIT 5) AS top_5_sample_data;

无法推断编码格式,因为该文件没有文件扩展名,因此显式将其配置为 parquet。 此外,压缩算法设置为 zstd

SELECT azure_storage.blob_put
        ('<account_name>'
        ,'<container_name>'
        ,'sample_parquet_data_copy_without_extension_with_zstd_compression'
        , top_5_sample_data
        ,'parquet'
        ,'zstd')
FROM (SELECT * FROM sample_data LIMIT 5) AS top_5_sample_data;

列出对 Azure 存储帐户的所有引用

此示例说明如何找出扩展可在此数据库中引用哪些 Azure 存储帐户 azure_storage ,以及用于访问每个存储帐户的身份验证类型,以及通过 azure_storage.account_user_add 函数授予哪些用户或角色的权限,以通过扩展提供的功能访问该 Azure 存储帐户。

SELECT * FROM azure_storage.account_list();

从 Azure Blob 存储引用上的用户或角色撤消访问权限

此示例演示如何从命名 <regular_user>的用户或角色撤消访问权限,以便此类 PostgreSQL 用户无法使用 azure_storage 扩展访问托管在引用的 Azure 存储帐户托管的容器中的 Blob。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

<regular_user> 必须设置为现有用户或角色的名称。

SELECT * FROM azure_storage.account_user_remove('<account_name>', '<regular_user>');

删除对存储帐户的引用

此示例演示如何删除对存储帐户的任何引用,以便当前数据库中的任何用户都无法使用 azure_storage 扩展功能访问该存储帐户。

<account_name> 必须设置为存储帐户的名称。 如果使用了前面的脚本,此值应与在这些脚本中设置为storage_account环境变量的任何值匹配。

SELECT azure_storage.account_remove('<account_name>');