使用无服务器 SQL 池查询 Azure Cosmos DB 数据

使用无服务器 SQL 池,可以近乎实时地分析使用 Azure Synapse Link 启用的 Azure Cosmos DB 容器中的数据,而不会影响事务工作负荷的性能。 它提供了一种熟悉的 Transact-SQL(T-SQL)语法,用于通过 T-SQL 接口查询 分析存储 中的数据和与各种商业智能(BI)和临时查询工具的集成连接。

查询 Azure Cosmos DB 时,可通过 OPENROWSET 函数支持完整的 SELECT 外围应用,其中包括大多数 SQL 函数和运算符。 还可以存储从 Azure Cosmos DB 读取数据的查询结果,以及 Azure Blob 存储或 Azure Data Lake Storage 中的数据,方法是使用创建外部表作为选择(CETAS)。 目前无法使用 CETAS 将无服务器 SQL 池查询结果存储到 Azure Cosmos DB。

本文介绍如何编写一个与无服务器 SQL 池配合使用的查询,该查询将从通过 Azure Synapse Link 启用的 Azure Cosmos DB 容器中查询数据。 然后,可以详细了解如何在 Azure Cosmos DB 容器上生成无服务器 SQL 池视图,并将其连接到 Power BI 模型。 本教程使用具有 Azure Cosmos DB 定义完善的架构的容器。 你还可以查看 Learn 模块,了解如何使用 SQL Serverless 为 Azure Synapse Analytics 查询 Azure Cosmos DB。

先决条件

  • 请确保准备好分析存储:
  • 请确保已应用所有 最佳做法,例如:
    • 请确保 Azure Cosmos DB 分析存储与无服务器 SQL 池位于同一区域。
    • 请确保客户端应用程序(Power BI、分析服务)与无服务器 SQL 池位于同一区域。
    • 如果要返回大量数据(大于 80 GB),请考虑使用 Analysis Services 等缓存层,并在 Analysis Services 模型中加载小于 80 GB 的分区。
    • 如果要使用字符串列筛选数据,请确保将 OPENROWSET 函数与具有最小可能类型的显式 WITH 子句一起使用。 例如,如果你知道该属性最多包含 5 个字符,请不要使用 VARCHAR(1000)

概述

无服务器 SQL 池可用于通过 OPENROWSET 函数查询 Azure Cosmos DB 分析存储。

OPENROWSET( 
       'CosmosDB',
       '<SQL connection string for Azure Cosmos DB>',
       <other parameters>
    )  [ < with clause > ] AS alias

Azure Cosmos DB 的 SQL 连接字符串包含以下组件:

  • account - 您所要目标的 Azure Cosmos DB 帐户的名称。
  • database - 在 OPENROWSET 语法中指定没有引号的容器名称。 如果容器名称包含特殊字符(例如短划线 -),则应用方括号([])括起来。
  • 区域 (可选) - Cosmos DB 分析存储的区域。 如果省略,则使用容器的主要区域。
  • endpoint - 所需的 Cosmos DB 终结点 URI(例如 https://<account name>.documents.azure.cn)。

可以从标准 Cosmos DB 连接字符串标识这些属性,例如:

AccountEndpoint=https://<database account name>.documents.azure.cn:443/;AccountKey=<database account master key>;

SQL 连接字符串的格式可以如下所示:

account=<database account name>;database=<database name>;region=<region name>;endpoint=<endpoint>

此连接字符串不包括连接到 Cosmos DB 分析存储所需的身份验证信息。 需要其他信息,具体取决于使用的身份验证类型:

  • 如果 OPENROWSET 使用工作区托管标识访问分析存储,则应添加 AuthType 属性。
  • 如果 OPENROWSET 使用内联帐户密钥,则应添加 key 该属性。 这样就可以查询 Azure Cosmos DB 集合,而无需准备凭据。
  • 而不是在连接字符串中包含身份验证信息,OPENROWSET 可以引用包含 Azure Cosmos DB 帐户密钥的凭据。 此方法可用于在 Azure Cosmos DB 集合上创建视图。

下面介绍这些选项。

借助无服务器 SQL 池,可以查询 Cosmos DB 分析存储并使用原始 Cosmos DB 帐户密钥进行身份验证,或者允许 Synapse 托管标识访问 Cosmos DB 分析存储。 在此方案中,可以使用以下语法:

OPENROWSET( 
       'CosmosDB',
       '<SQL connection string for Azure Cosmos DB>',
       <Container name>
    )  [ < with clause > ] AS alias

除了上述 SQL 连接字符串中的常用属性(帐户数据库区域终结点),还需要添加以下选项 之一

  • AuthType - 使用 Synapse 工作区托管标识访问 Cosmos DB 时,请设置 ManagedIdentity 此选项。
  • key - 访问 Cosmos DB 数据的主密钥,在不使用 Synapse 工作区托管标识的情况下使用。

下表显示了连接字符串的示例:

身份验证类型 连接字符串
Synapse 工作区托管标识 account=<account name>;database=<db name>;region=<region name>;endpoint=<endpoint>;AuthType=ManagedIdentity
Cosmos DB 帐户主密钥 account=<account name>;database=<db name>;region=<region name>;endpoint=<endpoint>;key=<account master key>

重要

请确保使用某种 UTF-8 数据库排序规则(例如 Latin1_General_100_CI_AS_SC_UTF8),因为 Azure Cosmos DB 分析存储中的字符串值会编码为 UTF-8 文本。 文件中的文本编码和排序规则不匹配可能会导致意外的文本转换错误。 可以使用 T-SQL 语句 alter database current collate Latin1_General_100_CI_AI_SC_UTF8 轻松地更改当前数据库的默认排序规则。

备注

无服务器 SQL 池不支持查询 Azure Cosmos DB 事务存储。

示例数据集

本文中的示例基于 欧洲疾病预防控制中心(ECDC)COVID-19 病例和 COVID-19开放研究数据集(CORD-19)的数据。

可以在这些页面上查看数据的许可证和结构。 还可以 下载 ECDC 和 CORD-19 数据集的示例数据。

若要按照本文中的说明使用无服务器 SQL 池来查询 Azure Cosmos DB 数据,请确保创建以下资源:

  • 一个启用了 Azure Synapse Link 的 Azure Cosmos DB 数据库帐户。
  • 一个名为 covid 的 Azure Cosmos DB 数据库。
  • 两个名为 EcdcCord19 的 Azure Cosmos DB 容器,其中加载了前面的示例数据集。

请注意,此连接不能保证性能表现,因为此帐户可能位于远离 Synapse SQL 终结点的区域。

利用自动架构推理浏览 Azure Cosmos DB 数据

在 Azure Cosmos DB 中浏览数据的最简单方法是使用自动架构推理功能。 通过省略 WITH 语句中的 OPENROWSET 子句,可以指示无服务器 SQL 池自动检测(推断)Azure Cosmos DB 容器的分析存储的架构。

重要

在脚本中,将以下值替换为你自己的值:

  • your-cosmosdb - Cosmos DB 帐户的名称
  • yourcosmosdbkey - 你的 Cosmos DB 帐户密钥
SELECT TOP 10 *
FROM OPENROWSET( 
       'CosmosDB',
       'Account=your-cosmosdb;Database=covid;Key=yourcosmosdbkey',
       Ecdc) as documents

在上一示例中,我们已指示无服务器 SQL 池连接到通过 Azure Cosmos DB 密钥(上一示例中的虚拟密钥)进行身份验证的 Azure Cosmos DB 帐户 covid 中的 MyCosmosDbAccount 数据库。 然后,我们访问了 Ecdc 区域中 China North 3 容器的分析存储。 由于没有特定属性的投影,因此 OPENROWSET 函数会返回 Azure Cosmos DB 项中的所有属性。

下表显示了此查询的结果(假定 Azure Cosmos DB 容器中的项具有 date_repcasesgeo_id 属性):

date_rep 大小写 地理标识符 (geo_id)
2020-08-13 254 RS
2020-08-12 235 RS
2020-08-11 163 RS

如果需要从同一个 Azure Cosmos DB 数据库中的另一个容器浏览数据,则可使用相同的连接字符串,将所需的容器作为第三个参数引用:

SELECT TOP 10 *
FROM OPENROWSET( 
       'CosmosDB',
       'Account=your-cosmosdb;Database=covid;Key=yourcosmosdbkey',
       Cord19) as cord19

显式指定架构

虽然 OPENROWSET 中的自动架构推理功能提供了简单易用的体验,但在某些业务场景中,可能需要你显式指定架构,以便从 Azure Cosmos DB 数据中仅读取相关属性。

OPENROWSET 函数使你可以显式指定要从容器中的数据读取哪些属性以及指定其数据类型。

假设我们已将一些数据从 ECDC COVID 数据集 中使用以下结构导入 Azure Cosmos DB:

{"date_rep":"2020-08-13","cases":254,"countries_and_territories":"Serbia","geo_id":"RS"}
{"date_rep":"2020-08-12","cases":235,"countries_and_territories":"Serbia","geo_id":"RS"}
{"date_rep":"2020-08-11","cases":163,"countries_and_territories":"Serbia","geo_id":"RS"}

Azure Cosmos DB 中的这些平面 JSON 文档可表示为 Synapse SQL 中的一组行和列。 使用 OPENROWSET 函数可以在 WITH 子句中指定要读取的属性的子集和确切的列类型:

SELECT TOP 10 *
FROM OPENROWSET(
      'CosmosDB',
      'Account=your-cosmosdb;Database=covid;Key=yourcosmosdbkey',
       Ecdc
    ) with ( date_rep varchar(20), cases bigint, geo_id varchar(6) ) as rows

此查询的结果可能如下表所示:

date_rep 大小写 地理标识符 (geo_id)
2020-08-13 254 RS
2020-08-12 235 RS
2020-08-11 163 RS

有关应用于 Azure Cosmos DB 值的 SQL 类型的详细信息,请参阅本文末尾的 Azure Cosmos DB 到 SQL 类型映射

创建视图

建议不要在 master 或默认数据库中创建视图,该操作也不受支持。 因此,你需要为视图创建用户数据库。

确定架构后,可以在 Azure Cosmos DB 数据的基础上准备视图。 应将 Azure Cosmos DB 帐户密钥置于单独的凭据中,从 OPENROWSET 函数引用此凭据。 不要在视图定义中保留你的帐户密钥。

CREATE CREDENTIAL MyCosmosDbAccountCredential
WITH IDENTITY = 'SHARED ACCESS SIGNATURE', SECRET = 'yourcosmosdbkey';
GO
CREATE OR ALTER VIEW Ecdc
AS SELECT *
FROM OPENROWSET(
      PROVIDER = 'CosmosDB',
      CONNECTION = 'Account=your-cosmosdb;Database=covid',
      OBJECT = 'Ecdc',
      SERVER_CREDENTIAL = 'MyCosmosDbAccountCredential'
    ) with ( date_rep varchar(20), cases bigint, geo_id varchar(6) ) as rows

不要使用没有显式定义的架构的 OPENROWSET,因为它可能会影响性能。 请确保使用列的最小可能大小,例如 VARCHAR(100),而不是使用默认的 VARCHAR(8000)。 应使用某些 UTF-8 排序规则作为默认数据库排序规则,或将其设置为显式列排序规则,以避免 UTF-8 转换问题。 排序规则 Latin1_General_100_BIN2_UTF8 可以在你使用某些字符串列来筛选数据时发挥最佳性能。

查询视图时,可能会遇到错误或意外结果。 视图引用列或对象可能已修改或不再存在。 需要手动调整视图定义,以便与基础架构更改保持一致。 请记住,在视图中使用自动架构推理和显式指定架构时,可能发生此情况。

查询嵌套对象

使用 Azure Cosmos DB,可以通过将数据模型作为嵌套对象或数组进行编写来表示更复杂的数据模型。 Azure Synapse Link for Azure Cosmos DB 的自动同步功能直接管理分析存储中的架构表示形式,包括处理那些允许从无服务器 SQL 池中进行丰富查询的嵌套数据类型。

例如, CORD-19 数据集具有遵循此结构的 JSON 文档:

{
    "paper_id": <str>,                   # 40-character sha1 of the PDF
    "metadata": {
        "title": <str>,
        "authors": <array of objects>    # list of author dicts, in order
        ...
     }
     ...
}

OPENROWSET 函数读取 Azure Cosmos DB 中的嵌套对象和数组时,它们会在查询结果中表示为 JSON 字符串。 使用 WITH 子句时,可以指定对象中嵌套值的路径:

SELECT TOP 10 *
FROM OPENROWSET( 
       'CosmosDB',
       'Account=your-cosmosdb;Database=covid;Key=yourcosmosdbkey',
       Cord19)
WITH (  paper_id    varchar(8000),
        title        varchar(1000) '$.metadata.title',
        metadata     varchar(max),
        authors      varchar(max) '$.metadata.authors'
) AS docs;

此查询的结果可能如下表所示:

论文编号 标题 元数据 作者
bb11206963e831f... 补充信息生态流行病学 {"title":"Supplementary Informati… [{"first":"Julien","last":"Mélade","suffix":"","af…
bb1206963e831f1... 在免疫研究中使用恢复期血清… {"title":"The Use of Convalescent… [{"first":"Antonio","last":"Lavazza","suffix":"", …
bb378eca9aac649... 蒂洛塞马埃斯库伦特姆(马拉玛)块茎和B… {"title":"Tylosema esculentum (Ma… [{"first":"Walter","last":"Chingwaru","suffix":"",…

若要了解详细信息,请参阅使用无服务器 SQL 池 分析 Azure Synapse Analytics 中的复杂数据类型查询 Parquet 和 JSON 文件中的嵌套类型

重要

如果在文本中出现了意外字符(例如 MÃÂ&copy;lade,而不是 Mélade),这表明您的数据库排序规则未设置为 UTF-8 排序规则。 可以使用 SQL 语句(如 )将ALTER DATABASE MyLdw COLLATE LATIN1_GENERAL_100_CI_AS_SC_UTF8为 UTF-8 排序规则。

扁平化嵌套数组

Azure Cosmos DB 数据可能具有与 CORD-19 数据集中的 authors 数组类似的嵌套子数组:

{
    "paper_id": <str>,                      # 40-character sha1 of the PDF
    "metadata": {
        "title": <str>,
        "authors": [                        # list of author dicts, in order
            {
                "first": <str>,
                "middle": <list of str>,
                "last": <str>,
                "suffix": <str>,
                "affiliation": <dict>,
                "email": <str>
            },
            ...
        ],
        ...
}

在某些情况下,可能需要将顶部项(元数据)中的属性与数组 (authors) 的所有元素进行联接。 无服务器 SQL 池可用于通过对嵌套数组应用 OPENJSON 函数来平展嵌套结构:

SELECT
    *
FROM
    OPENROWSET(
      'CosmosDB',
      'Account=your-cosmosdb;Database=covid;Key=yourcosmosdbkey',
       Cord19
    ) WITH ( title varchar(1000) '$.metadata.title',
             authors varchar(max) '$.metadata.authors' ) AS docs
      CROSS APPLY OPENJSON ( authors )
                  WITH (
                       first varchar(50),
                       last varchar(50),
                       affiliation nvarchar(max) as json
                  ) AS a

此查询的结果可能如下表所示:

标题 作者 第一 最后 隶属关系
补充信息生态流行病学... [{"first":"Julien","last":"Mélade","suffix":"","affiliation":{"laboratory":"Centre de Recher… 朱利安 梅拉德 {"laboratory":"Centre de Recher…
补充信息生态流行病学... [{"first":"Nicolas","last":"4#","suffix":"","affiliation":{"laboratory":"","institution":"U… 尼古拉斯 4# {"laboratory":"","institution":"U…
补充信息生态流行病学... [{"first":"Beza","last":"Ramazindrazana","suffix":"","affiliation":{"laboratory":"Centre de Recher… Beza Ramazindrazana {"laboratory":"Centre de Recher…
补充信息生态流行病学… [{"first":"Olivier","last":"Flores","suffix":"","affiliation":{"laboratory":"UMR C53 CIRAD, … 奥利维尔 弗洛雷斯 {"laboratory":"UMR C53 CIRAD, …

重要

如果在文本中出现了意外字符(例如 MÃÂ&copy;lade,而不是 Mélade),这表明您的数据库排序规则未设置为 UTF-8 排序规则。 可以使用 SQL 语句(如 )将ALTER DATABASE MyLdw COLLATE LATIN1_GENERAL_100_CI_AS_SC_UTF8为 UTF-8 排序规则。

Azure Cosmos DB 到 SQL 类型的映射

尽管 Azure Cosmos DB 事务存储与架构无关,但分析存储已架构化,因此可以针对分析查询性能进行优化。 使用 Azure Synapse Link 的自动同步功能,Azure Cosmos DB 可以直接管理分析存储中的架构表示形式,包括处理嵌套数据类型。 由于无服务器 SQL 池会查询分析存储,因此必须了解如何将 Azure Cosmos DB 输入数据类型映射到 SQL 数据类型。

SQL (Core) API 的 Azure Cosmos DB 帐户支持数字、字符串、布尔值、Null、嵌套对象或数组 JSON 属性类型。 如果在 WITH 中使用 OPENROWSET 子句,则需选择与这些 JSON 类型匹配的 SQL 类型。 下表显示了应该用于 Azure Cosmos DB 中的不同属性类型的 SQL 列类型。

Azure Cosmos DB 属性类型 SQL 列类型
布尔
整数 bigint
小数 浮动
字符串 varchar(UTF-8 数据库排序规则)
日期时间(ISO 格式的字符串) varchar(30)
日期时间(UNIX 时间戳) bigint
any SQL type
嵌套对象或数组 varchar(max)(UTF-8 数据库排序规则),序列化为 JSON 文本

全保真架构

Azure Cosmos DB 全保真架构记录容器中每个属性的值及其最佳匹配类型。 具有全保真架构的容器中的 OPENROWSET 函数同时在每个单元格中提供类型和实际值。 假设下面的查询从具有全保真架构的容器中读取项:

SELECT *
FROM OPENROWSET(
      'CosmosDB',
      'account=MyCosmosDbAccount;database=covid;region=chinanorth3;key=C0Sm0sDbKey==',
       Ecdc
    ) as rows

此查询的结果会返回格式化为 JSON 文本的类型和值:

date_rep 大小写 地理标识符 (geo_id)
{“date”:“2020-08-13”} {“int32”:“254”} {“string”:“RS”}
{“date”:“2020-08-12”} {“int32”:“235”} {“string”:“RS”}
{“date”:“2020-08-11”} {“int32”:“316”} {“string”:“RS”}
{“date”:“2020-08-10”} {“int32”:“281”} {“string”:“RS”}
{“date”:“2020-08-09”} {“int32”:“295”} {“string”:“RS”}
{“string”:“2020/08/08”} {“int32”:“312”} {“string”:“RS”}
{“date”:“2020-08-07”} {“float64”:“339.0”} {“string”:“RS”}

对于每个值,你都可以查看 Azure Cosmos DB 容器项中标识的类型。 date_rep 属性的大多数值包含 date 值,但部分值在 Azure Cosmos DB 中错误地存储为字符串。 全保真架构会返回类型设置正确的 date 值和格式设置不正确的 string 值。

病例数存储为 int32 值,但有一个作为十进制数输入的值。 该值有 float64 类型。 如果某些值超过了最大的 int32 数,则会将其存储为 int64 类型。 此示例中的所有 geo_id 值都存储为 string 类型。

重要

没有 OPENROWSET 子句的 WITH 函数同时公开了具有预期类型的值和输入的类型错误的值。 此函数旨在用于数据浏览,而不用于报告。 请勿分析此函数返回的 JSON 值来生成报表。 使用显式 WITH 子句 创建报表。 你应该清理 Azure Cosmos DB 容器中具有错误类型的值,以便在全保真分析存储中应用更正。

要查询适用于 MongoDB 帐户的 Azure Cosmos DB,您可以在 什么是 Azure Cosmos DB 分析存储 中详细了解分析存储中完整精确的架构表示形式及其扩展属性名称。

查询具有全保真架构的项

查询全保真架构时,需要在 WITH 子句中显式指定 SQL 类型和预期的 Azure Cosmos DB 属性类型。

在下面的示例中,我们假设 stringgeo_id 属性的正确类型,int32cases 属性的正确类型:

SELECT geo_id, cases = SUM(cases)
FROM OPENROWSET(
      'CosmosDB'
      'account=MyCosmosDbAccount;database=covid;region=chinanorth3;key=C0Sm0sDbKey==',
       Ecdc
    ) WITH ( geo_id VARCHAR(50) '$.geo_id.string',
             cases INT '$.cases.int32'
    ) as rows
GROUP BY geo_id

geo_idcases 的其他类型的值会作为 NULL 值返回。 此查询将只引用在表达式中具有指定类型 (cases) 的 cases.int32

如果有其他类型(cases.int64cases.float64)的无法在 Azure Cosmos DB 容器中清除的值,则需在 WITH 子句中显式引用这些值,并将结果组合在一起。 以下查询会聚合存储在 int32 列中的 int64float64cases

SELECT geo_id, cases = SUM(cases_int) + SUM(cases_bigint) + SUM(cases_float)
FROM OPENROWSET(
      'CosmosDB',
      'account=MyCosmosDbAccount;database=covid;region=chinanorth3;key=C0Sm0sDbKey==',
       Ecdc
    ) WITH ( geo_id VARCHAR(50) '$.geo_id.string', 
             cases_int INT '$.cases.int32',
             cases_bigint BIGINT '$.cases.int64',
             cases_float FLOAT '$.cases.float64'
    ) as rows
GROUP BY geo_id

在此示例中,病例的数量存储为 int32int64float64 值。 必须提取所有值才能计算每个国家或地区的病例数。

故障排除

查看 自助页 ,查找已知问题或故障排除步骤,以帮助解决 Azure Cosmos DB 查询的潜在问题。