语句执行 API:在仓库上运行 SQL

重要

要访问 Databricks REST API,必须进行身份验证

本教程介绍如何使用 Databricks SQL 语句执行 API 2.0 从 Databricks SQL 仓库运行 SQL 语句。

若要查看 Databricks SQL 语句执行 API 2.0 版本参考,请参阅语句执行

开始之前

在开始学习本教程之前,请确保具备:

  • Databricks CLI 版本 0.205 或更高版本或者 curl,如下所示:

    • Databricks CLI 是一个用于发送和接收 Databricks REST API 请求和响应的命令行工具。 如果使用 Databricks CLI 版本 0.205 或更高版本,则必须将其配置为使用 Azure Databricks 工作区进行身份验证。 请参阅安装或更新 Databricks CLIDatabricks CLI 的身份验证

      例如,要使用 Databricks 个人访问令牌身份验证进行身份验证,请创建个人访问令牌,如下所示:

      1. 在 Azure Databricks 工作区中,单击顶部栏中的 Azure Databricks 用户名,然后从下拉列表中选择“设置”
      2. 单击“开发人员”。
      3. 在“访问令牌”旁边,单击“管理”。
      4. 单击“生成新令牌”。
      5. (可选)输入有助于将来识别此令牌的注释,并将令牌的默认生存期更改为 90 天。 若要创建没有生存期的令牌(不建议),请将“生存期(天)”框留空(保留空白)。
      6. 单击“生成” 。
      7. 将显示的令牌复制到安全位置,然后单击“完成”。

      注意

      请务必将复制的令牌保存到安全的位置。 请勿与他人共享复制的令牌。 如果丢失了复制的令牌,你将无法重新生成完全相同的令牌, 而必须重复此过程来创建新令牌。 如果丢失了复制的令牌,或者认为令牌已泄露,Databricks 强烈建议通过单击“访问令牌”页上令牌旁边的垃圾桶(撤销)图标立即从工作区中删除该令牌。

      如果你无法在工作区中创建或使用令牌,可能是因为工作区管理员已禁用令牌或未授予你创建或使用令牌的权限。 请与工作区管理员联系,或参阅以下内容:

      然后,要使用 Databricks CLI 为个人访问令牌创建 Azure Databricks 配置文件,请执行以下操作:

      注意

      以下过程将使用 Databricks CLI 创建名为 DEFAULT 的 Azure Databricks 配置文件。 如果已具有 DEFAULT 配置文件,此过程将覆盖现有的 DEFAULT 配置文件。

      要检查是否已有 DEFAULT 配置文件,并查看此配置文件的设置(如果存在),请使用 Databricks CLI 运行命令 databricks auth env --profile DEFAULT

      要使用除 DEFAULT 以外的名称创建配置文件,请将以下 databricks configure 命令中 --profile DEFAULTDEFAULT 部分替换为其他配置文件名称。

      1. 使用 Databricks CLI 创建名为 DEFAULT 的 Azure Databricks 配置文件,它使用 Azure Databricks 个人访问令牌身份验证。 为此,请运行以下命令:

        databricks configure --profile DEFAULT
        
      2. 对于提示Databricks 主机,请输入 Azure Databricks 按工作区 URL,例如https://adb-1234567890123456.7.databricks.azure.cn

      3. 对于提示个人访问令牌,请输入工作区的 Azure Databricks 个人访问令牌。

      在本教程的 Databricks CLI 示例中,请注意以下事项:

      • 本教程假设你的本地开发计算机上有一个环境变量 DATABRICKS_SQL_WAREHOUSE_ID。 此环境变量表示 Databricks SQL 仓库的 ID。 此 ID 是仓库的“HTTP 路径”字段中 /sql/1.0/warehouses/ 后面的字母和数字字符串。 若要了解如何获取仓库的 HTTP 路径值,请参阅获取 Azure Databricks 计算资源的连接详细信息
      • 如果使用 Windows 命令行界面而不是 Unix、Linux 或 macOS 的命令行界面,请将 \ 替换为 ^,并将 ${...} 替换为 %...%
      • 如果使用 Windows 命令行界面而不是 Unix、Linux 或 macOS 的命令行界面,请在 JSON 文档声明中,将左右 ' 替换为 ",并将内部 " 替换为 \"
    • curl 是一个用于发送和接收 REST API 请求和响应的命令行工具。 另请参阅安装 curl。 或者,改编本教程的 curl 示例,以便与 HTTPie 等类似工具配合使用。

      在本教程的 curl 示例中,请注意以下事项:

      • 可以使用 .netrc 文件而不是 --header "Authorization: Bearer ${DATABRICKS_TOKEN}"。 如果使用 .netrc 文件,请将 --header "Authorization: Bearer ${DATABRICKS_TOKEN}" 替换为 --netrc
      • 如果使用 Windows 命令行界面而不是 Unix、Linux 或 macOS 的命令行界面,请将 \ 替换为 ^,并将 ${...} 替换为 %...%
      • 如果使用 Windows 命令行界面而不是 Unix、Linux 或 macOS 的命令行界面,请在 JSON 文档声明中,将左右 ' 替换为 ",并将内部 " 替换为 \"

      此外,对于本教程的 curl 示例,本教程假定你的本地开发计算机上有以下环境变量:

      • DATABRICKS_HOST,表示 Azure Databricks 工作区的工作区实例名称,例如 adb-1234567890123456.7.databricks.azure.cn
      • DATABRICKS_TOKEN,表示 Azure Databricks 工作区用户的 Azure Databricks 个人访问令牌
      • DATABRICKS_SQL_WAREHOUSE_ID,表示 Databricks SQL 仓库的 ID。 此 ID 是仓库的“HTTP 路径”字段中 /sql/1.0/warehouses/ 后面的字母和数字字符串。 若要了解如何获取仓库的 HTTP 路径值,请参阅获取 Azure Databricks 计算资源的连接详细信息

      注意

      作为安全最佳做法,在使用自动化工具、系统、脚本和应用进行身份验证时,Databricks 建议使用属于服务主体(而不是工作区用户)的个人访问令牌。 若要为服务主体创建令牌,请参阅管理服务主体的令牌

      要创建 Azure Databricks 个人访问令牌,请执行以下操作:

      1. 在 Azure Databricks 工作区中,单击顶部栏中的 Azure Databricks 用户名,然后从下拉列表中选择“设置”
      2. 单击“开发人员”。
      3. 在“访问令牌”旁边,单击“管理”。
      4. 单击“生成新令牌”。
      5. (可选)输入有助于将来识别此令牌的注释,并将令牌的默认生存期更改为 90 天。 若要创建没有生存期的令牌(不建议),请将“生存期(天)”框留空(保留空白)。
      6. 单击“生成” 。
      7. 将显示的令牌复制到安全位置,然后单击“完成”。

      注意

      请务必将复制的令牌保存到安全的位置。 请勿与他人共享复制的令牌。 如果丢失了复制的令牌,你将无法重新生成完全相同的令牌, 而必须重复此过程来创建新令牌。 如果丢失了复制的令牌,或者认为令牌已泄露,Databricks 强烈建议通过单击“访问令牌”页上令牌旁边的垃圾桶(撤销)图标立即从工作区中删除该令牌。

      如果你无法在工作区中创建或使用令牌,可能是因为工作区管理员已禁用令牌或未授予你创建或使用令牌的权限。 请与工作区管理员联系,或参阅以下内容:

      警告

      Databricks 强烈建议不要在脚本中将信息硬编码,因为这些敏感信息可以通过版本控制系统以纯文本形式公开。 Databricks 建议改用开发计算机上设置的方法,例如使用环境变量。 从脚本中删除此类硬编码信息还有助于提高这些脚本的可移植性。

  • 本教程假设你还拥有 jq,一个用于查询 JSON 响应有效负载的命令行处理程序,在你每次调用 Databricks SQL 语句执行 API 后,Databricks SQL 语句执行 API 会向你返回这些有效负载。 请参阅下载 jq

  • 你必须至少有一个可对其执行 SQL 语句的表。 本教程基于 samples 目录内 tpch 架构(也称为数据库)中的 lineitem 表。 如果你无权从工作区访问此目录、架构或表,请在整篇教程中将其替换为你自己的对象。

步骤 1:执行 SQL 语句并将数据结果保存为 JSON

运行以下命令来执行以下操作:

  1. 使用指定的 SQL 仓库以及指定的令牌(如果使用 curl),从 samples 目录中的 tcph 架构中 lineitem 表的前两行查询三列。
  2. 以 JSON 格式将响应有效负载保存在当前工作目录内名为 sql-execution-response.json 的文件中。
  3. 输出 sql-execution-response.json 文件的内容。
  4. 设置一个名为 SQL_STATEMENT_ID 的局部环境变量。 此变量包含相应 SQL 语句的 ID。 可以根据需要使用此 SQL 语句 ID 获取有关该语句的信息,如步骤 2 中所示。 还可以在 Databricks SQL 控制台的查询历史记录部分或者通过调用查询历史记录 API 来查看此 SQL 语句并获取其语句 ID。
  5. 设置一个名为 NEXT_CHUNK_EXTERNAL_LINK 的附加局部环境变量,其中包含用于获取下一个 JSON 数据区块的 API URL 片段。 如果响应数据太大,Databricks SQL 语句执行 API 将以区块的形式提供响应。 可以使用此 API URL 片段获取下一个数据区块,如步骤 2 中所示。 如果没有下一个区块,则此环境变量设置为 null
  6. 输出 SQL_STATEMENT_IDNEXT_CHUNK_INTERNAL_LINK 环境变量的值。

Databricks CLI

databricks api post /api/2.0/sql/statements \
--profile <profile-name> \
--json '{
  "warehouse_id": "'"$DATABRICKS_SQL_WAREHOUSE_ID"'",
  "catalog": "samples",
  "schema": "tpch",
  "statement": "SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem WHERE l_extendedprice > :extended_price AND l_shipdate > :ship_date LIMIT :row_limit",
  "parameters": [
    { "name": "extended_price", "value": "60000", "type": "DECIMAL(18,2)" },
    { "name": "ship_date", "value": "1995-01-01", "type": "DATE" },
    { "name": "row_limit", "value": "2", "type": "INT" }
  ]
}' \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export SQL_STATEMENT_ID=$(jq -r .statement_id 'sql-execution-response.json') \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .result.next_chunk_internal_link 'sql-execution-response.json') \
&& echo SQL_STATEMENT_ID=$SQL_STATEMENT_ID \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request POST \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/ \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--header "Content-Type: application/json" \
--data '{
  "warehouse_id": "'"$DATABRICKS_SQL_WAREHOUSE_ID"'",
  "catalog": "samples",
  "schema": "tpch",
  "statement": "SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem WHERE l_extendedprice > :extended_price AND l_shipdate > :ship_date LIMIT :row_limit",
  "parameters": [
    { "name": "extended_price", "value": "60000", "type": "DECIMAL(18,2)" },
    { "name": "ship_date", "value": "1995-01-01", "type": "DATE" },
    { "name": "row_limit", "value": "2", "type": "INT" }
  ]
}' \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export SQL_STATEMENT_ID=$(jq -r .statement_id 'sql-execution-response.json') \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .result.next_chunk_internal_link 'sql-execution-response.json') \
&& echo SQL_STATEMENT_ID=$SQL_STATEMENT_ID \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

在上面的请求中:

  • 参数化查询由每个查询参数的名称组成,前面有一个冒号(例如,:extended_price),在 parameters 数组中有一个匹配的 namevalue 对象。 也可以指定一个可选 type 值,如果未指定,则默认值为 STRING

    警告

    Databricks 强烈建议对 SQL 语句使用参数,这是最佳做法。

    如果将 Databricks SQL 语句执行 API 与动态生成 SQL 的应用程序一起使用,则可能招致 SQL 注入攻击。 例如,如果你根据用户界面中的用户选择生成 SQL 代码,并且不采取适当的措施,攻击者可能会注入恶意 SQL 代码来更改初始查询的逻辑,从而读取、更改或删除敏感数据。

    参数化查询将输入参数与 SQL 代码的其余部分分开处理,并将这些参数解释为文本值,从而帮助防范 SQL 注入攻击。 参数还有助于实现代码可重用性。

  • 默认情况下,所有返回的数据都采用 JSON 数组格式,所有 SQL 语句的数据结果的默认位置都在响应有效负载中。 若要使此行为成为显式行为,请将 "format":"JSON_ARRAY","disposition":"INLINE" 添加到请求有效负载。 如果你尝试在响应有效负载中返回大于 25 MiB 的数据结果,则会返回失败状态并取消 SQL 语句。 对于大于 25 MiB 的数据结果,可以使用外部链接,而不要尝试在响应有效负载中返回结果,如步骤 3 中所示。

  • 该命令将响应有效负载的内容存储到本地文件。 Databricks SQL 语句执行 API 无法直接支持本地数据存储。

  • 默认情况下,在 10 秒后,如果 SQL 语句尚未通过仓库完成执行,则 Databricks SQL 语句执行 API 仅返回 SQL 语句 ID 及其当前状态,而不返回语句的结果。 若要更改此行为,请将 "wait_timeout" 添加到请求并将其设置为 "<x>s",其中 <x> 可以介于 550 秒之间(含),例如 "50s"。 若要立即返回 SQL 语句 ID 及其当前状态,请将 wait_timeout 设置为 0s

  • 默认情况下,如果达到超时期限,SQL 语句会继续运行。 若要在达到超时期限时取消 SQL 语句,请将 "on_wait_timeout":"CANCEL" 添加到请求有效负载。

  • 若要限制返回的字节数,请将 "byte_limit" 添加到请求并将其设置为字节数,例如 1000

  • 若要限制返回的行数,而不是向 statement 添加 LIMIT 子句,可以将 "row_limit" 添加到请求并将其设置为行数,例如 "statement":"SELECT * FROM lineitem","row_limit":2

  • 如果结果大于指定的 byte_limitrow_limit,则 truncated 字段在响应有效负载中设置为 true

如果在等待超时结束之前提供了语句的结果,则响应如下所示:

{
  "manifest": {
    "chunks": [
      {
        "chunk_index": 0,
        "row_count": 2,
        "row_offset": 0
      }
    ],
    "format": "JSON_ARRAY",
    "schema": {
      "column_count": 3,
      "columns": [
        {
          "name": "l_orderkey",
          "position": 0,
          "type_name": "LONG",
          "type_text": "BIGINT"
        },
        {
          "name": "l_extendedprice",
          "position": 1,
          "type_name": "DECIMAL",
          "type_precision": 18,
          "type_scale": 2,
          "type_text": "DECIMAL(18,2)"
        },
        {
          "name": "l_shipdate",
          "position": 2,
          "type_name": "DATE",
          "type_text": "DATE"
        }
      ]
    },
    "total_chunk_count": 1,
    "total_row_count": 2,
    "truncated": false
  },
  "result": {
    "chunk_index": 0,
    "data_array": [
      [
        "2",
        "71433.16",
        "1997-01-28"
      ],
      [
        "7",
        "86152.02",
        "1996-01-15"
      ]
    ],
    "row_count": 2,
    "row_offset": 0
  },
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "SUCCEEDED"
  }
}

如果等待超时在提供语句的结果之前结束,则响应如下所示:

{
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "PENDING"
  }
}

如果语句的结果数据太大(例如在本例中,运行 SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem LIMIT 300000 后获得的数据),则结果数据将被分块,如下所示。 请注意,为简洁起见,此处的 "...": "..." 表示省略的结果:

{
  "manifest": {
    "chunks": [
      {
        "chunk_index": 0,
        "row_count": 188416,
        "row_offset": 0
      },
      {
        "chunk_index": 1,
        "row_count": 111584,
        "row_offset": 188416
      }
    ],
    "format":"JSON_ARRAY",
    "schema": {
      "column_count":3,
      "columns": [
        {
          "...": "..."
        }
      ]
    },
    "total_chunk_count": 2,
    "total_row_count": 300000,
    "truncated": false
  },
  "result": {
    "chunk_index": 0,
    "data_array": [
      [
        "2",
        "71433.16",
        "1997-01-28"
      ],
      [
        "..."
      ]
    ],
    "next_chunk_index": 1,
    "next_chunk_internal_link": "/api/2.0/sql/statements/00000000-0000-0000-0000-000000000000/result/chunks/1?row_offset=188416",
    "row_count": 188416,
    "row_offset": 0
  },
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "SUCCEEDED"
  }
}

步骤 2:获取语句的当前执行状态并将数据结果保存为 JSON

可以使用 SQL 语句的 ID 获取该语句的当前执行状态,如果执行成功,则获取该语句的结果。 如果你忘记了语句的 ID,可以从 Databricks SQL 控制台的查询历史记录部分或者通过调用查询历史记录 API 来获取此 ID。 例如,可以不断轮询此命令,并在每次轮询时检查执行是否成功。

若要获取 SQL 语句的当前执行状态,并在执行成功时获取该语句的结果和用于获取任何下一个 JSON 数据区块的 API URL 片段,请运行以下命令。 此命令假设本地开发计算机上有一个名为 SQL_STATEMENT_ID 的环境变量,该变量设置为在上一步骤中获取的 SQL 语句 ID 值。 当然,可以将以下命令中的 ${SQL_STATEMENT_ID} 替换为 SQL 语句的硬编码 ID。

Databricks CLI

databricks api get /api/2.0/sql/statements/${SQL_STATEMENT_ID} \
--profile <profile-name> \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .result.next_chunk_internal_link 'sql-execution-response.json') \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request GET \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/${SQL_STATEMENT_ID} \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .result.next_chunk_internal_link 'sql-execution-response.json') \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

如果 NEXT_CHUNK_INTERNAL_LINK 设置为非 null 值,你可以使用它来获取下一个数据区块,依此类推,例如使用以下命令:

Databricks CLI

databricks api get /${NEXT_CHUNK_INTERNAL_LINK} \
--profile <profile-name> \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .next_chunk_internal_link 'sql-execution-response.json') \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request GET \
https://${DATABRICKS_HOST}${NEXT_CHUNK_INTERNAL_LINK} \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export NEXT_CHUNK_INTERNAL_LINK=$(jq -r .next_chunk_internal_link 'sql-execution-response.json') \
&& echo NEXT_CHUNK_INTERNAL_LINK=$NEXT_CHUNK_INTERNAL_LINK

可以一遍又一遍地运行上述命令以获得下一个区块,依此类推。 请注意,一旦提取最后一个区块,SQL 语句就会结束。 在结束之后,无法使用该语句的 ID 来获取其当前状态或提取更多区块。

本部分演示一个可选配置,它使用 EXTERNAL_LINKS 处置来检索大型数据集。 SQL 语句结果数据的默认位置(处置)位于响应有效负载中,但这些结果限制为 25 MiB。 将 disposition 设置为 EXTERNAL_LINKS 后,响应将包含可用于通过标准 HTTP 提取结果数据区块的 URL。 这些 URL 指向工作区的内部 DBFS,结果区块暂时存储在其中。

警告

Databricks 强烈建议保护 EXTERNAL_LINKS 处置返回的 URL 和令牌。

使用 EXTERNAL_LINKS 处置时,会生成一个共享访问签名 (SAS) URL,使用它可以直接从 Azure 存储下载结果。 由于此 SAS URL 中嵌入了一个短期 SAS 令牌,因此应同时保护 SAS URL 和 SAS 令牌。

由于已使用嵌入的临时 SAS 令牌生成了 SAS URL,因此不得在下载请求中设置 Authorization 标头。

可以根据请求通过创建支持案例来禁用 EXTERNAL_LINKS 处置。

另请参阅安全最佳做法

备注

为特定 SQL 语句 ID 设置响应有效负载输出格式和行为后,无法对其进行更改。

在此模式下,可以使用 API 来存储必须通过 HTTP 单独查询的 JSON 格式 (JSON)、CSV 格式 (CSV) 或 Apache Arrow 格式 (ARROW_STREAM) 的结果数据。 另外,使用此模式时,无法将结果数据内联到响应有效负载中。

以下命令演示如何使用 EXTERNAL_LINKS 和 Apache Arrow 格式。 使用此模式,而不是步骤 1 中演示的类似查询:

Databricks CLI

databricks api post /api/2.0/sql/statements/ \
--profile <profile-name> \
--json '{
  "warehouse_id": "'"$DATABRICKS_SQL_WAREHOUSE_ID"'",
  "catalog": "samples",
  "schema": "tpch",
  "format": "ARROW_STREAM",
  "disposition": "EXTERNAL_LINKS",
  "statement": "SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem WHERE l_extendedprice > :extended_price AND l_shipdate > :ship_date LIMIT :row_limit",
  "parameters": [
    { "name": "extended_price", "value": "60000", "type": "DECIMAL(18,2)" },
    { "name": "ship_date", "value": "1995-01-01", "type": "DATE" },
    { "name": "row_limit", "value": "100000", "type": "INT" }
  ]
}' \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export SQL_STATEMENT_ID=$(jq -r .statement_id 'sql-execution-response.json') \
&& echo SQL_STATEMENT_ID=$SQL_STATEMENT_ID

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request POST \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/ \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--header "Content-Type: application/json" \
--data '{
  "warehouse_id": "'"$DATABRICKS_SQL_WAREHOUSE_ID"'",
  "catalog": "samples",
  "schema": "tpch",
  "format": "ARROW_STREAM",
  "disposition": "EXTERNAL_LINKS",
  "statement": "SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem WHERE l_extendedprice > :extended_price AND l_shipdate > :ship_date LIMIT :row_limit",
  "parameters": [
    { "name": "extended_price", "value": "60000", "type": "DECIMAL(18,2)" },
    { "name": "ship_date", "value": "1995-01-01", "type": "DATE" },
    { "name": "row_limit", "value": "100000", "type": "INT" }
  ]
}' \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json' \
&& export SQL_STATEMENT_ID=$(jq -r .statement_id 'sql-execution-response.json') \
&& echo SQL_STATEMENT_ID=$SQL_STATEMENT_ID

响应如下所示:

{
  "manifest": {
    "chunks": [
      {
        "byte_count": 2843848,
        "chunk_index": 0,
        "row_count": 100000,
        "row_offset": 0
      }
    ],
    "format": "ARROW_STREAM",
    "schema": {
      "column_count": 3,
      "columns": [
        {
          "name": "l_orderkey",
          "position": 0,
          "type_name": "LONG",
          "type_text": "BIGINT"
        },
        {
          "name": "l_extendedprice",
          "position": 1,
          "type_name": "DECIMAL",
          "type_precision": 18,
          "type_scale": 2,
          "type_text": "DECIMAL(18,2)"
        },
        {
          "name": "l_shipdate",
          "position": 2,
          "type_name": "DATE",
          "type_text": "DATE"
        }
      ]
    },
    "total_byte_count": 2843848,
    "total_chunk_count": 1,
    "total_row_count": 100000,
    "truncated": false
  },
  "result": {
    "external_links": [
      {
        "byte_count": 2843848,
        "chunk_index": 0,
        "expiration": "<url-expiration-timestamp>",
        "external_link": "<url-to-data-stored-externally>",
        "row_count": 100000,
        "row_offset": 0
      }
    ]
  },
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "SUCCEEDED"
  }
}

如果请求超时,则响应如下所示:

{
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "PENDING"
  }
}

若要获取该语句的当前执行状态,并在执行成功时获取该语句的结果,请运行以下命令:

Databricks CLI

databricks api get /api/2.0/sql/statements/${SQL_STATEMENT_ID} \
--profile <profile-name> \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json'

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request GET \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/${SQL_STATEMENT_ID} \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json'

如果响应足够大(例如在本例中,在不限制行的情况下运行 SELECT l_orderkey, l_extendedprice, l_shipdate FROM lineitem 后获得的响应),则响应将包含多个区块,如以下示例所示。 请注意,为简洁起见,此处的 "...": "..." 表示省略的结果:

{
  "manifest": {
    "chunks": [
      {
        "byte_count": 11469280,
        "chunk_index": 0,
        "row_count": 403354,
        "row_offset": 0
      },
      {
        "byte_count": 6282464,
        "chunk_index": 1,
        "row_count": 220939,
        "row_offset": 403354
      },
      {
        "...": "..."
      },
      {
        "byte_count": 6322880,
        "chunk_index": 10,
        "row_count": 222355,
        "row_offset": 3113156
      }
    ],
    "format":"ARROW_STREAM",
    "schema": {
      "column_count": 3,
      "columns": [
        {
          "...": "..."
        }
      ]
    },
    "total_byte_count": 94845304,
    "total_chunk_count": 11,
    "total_row_count": 3335511,
    "truncated": false
  },
  "result": {
    "external_links": [
      {
        "byte_count": 11469280,
        "chunk_index": 0,
        "expiration": "<url-expiration-timestamp>",
        "external_link": "<url-to-data-stored-externally>",
        "next_chunk_index": 1,
        "next_chunk_internal_link": "/api/2.0/sql/statements/00000000-0000-0000-0000-000000000000/result/chunks/1?row_offset=403354",
        "row_count": 403354,
        "row_offset": 0
      }
    ]
  },
  "statement_id": "00000000-0000-0000-0000-000000000000",
  "status": {
    "state": "SUCCEEDED"
  }
}

若要下载存储内容的结果,可以运行以下 curl 命令,同时使用 external_link 对象中的 URL 并指定要将文件下载到的位置。 不要在此命令中包含你的 Azure Databricks 令牌:

curl "<url-to-result-stored-externally>" \
--output "<path/to/download/the/file/locally>"

若要下载流式传输内容结果的特定区块,可以使用下列方法之一:

  • 下一个区块的响应有效负载中的 next_chunk_index 值(如果有下一个区块)。
  • 如果有多个区块,则响应有效负载清单中的一个区块索引可用于任何可用区块。

例如,若要在上面的响应中获取 chunk_index10 的区块,请运行以下命令:

Databricks CLI

databricks api get /api/2.0/sql/statements/${SQL_STATEMENT_ID}/result/chunks/10 \
--profile <profile-name> \
> 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json'

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request GET \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/${SQL_STATEMENT_ID}/result/chunks/10 \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}" \
--output 'sql-execution-response.json' \
&& jq . 'sql-execution-response.json'

注意

运行上述命令会返回一个新的 SAS URL。

若要下载存储的区块,请使用 external_link 对象中的 URL。

有关 Apache Arrow 格式的详细信息,请参阅:

步骤 4:取消 SQL 语句的执行

如果需要取消尚未成功的 SQL 语句,请运行以下命令:

Databricks CLI

databricks api post /api/2.0/sql/statements/${SQL_STATEMENT_ID}/cancel \
--profile <profile-name> \
--json '{}'

<profile-name> 替换为用于进行身份验证的 Azure Databricks 配置文件的名称。

curl

curl --request POST \
https://${DATABRICKS_HOST}/api/2.0/sql/statements/${SQL_STATEMENT_ID}/cancel \
--header "Authorization: Bearer ${DATABRICKS_TOKEN}"

安全最佳做法

Databricks SQL 语句执行 API 使用端到端传输层安全性 (TLS) 加密和短期凭据(例如 SAS 令牌)来提高数据传输的安全性。

此安全模型中有多个层。 在传输层,只能使用 TLS 1.2 或更高版本调用 Databricks SQL 语句执行 API。 另外,Databricks SQL 语句执行 API 的调用方必须使用有效的 Azure Databricks 个人访问令牌Microsoft Entra ID(前 Azure Active Directory)令牌进行身份验证,该令牌需映射到有权使用 Databricks SQL 的用户。 此用户必须对所用的特定 SQL 仓库拥有可以使用访问权限,可以使用 IP 访问列表限制访问。 这适用于对 Databricks SQL 语句执行 API 发出的所有请求。 此外,要执行语句,经过身份验证的用户必须对每个语句中使用的数据对象(例如表、视图和函数)拥有权限。 此要求是通过 Unity Catalog 中的现有访问控制机制或使用表 ACL 强制实施的。 (请参阅“使用 Unity 目录进行数据管理”,以获取更多详情。)这也意味着,只有执行语句的用户才能对语句的结果发出提取请求。

Databricks 建议每当结合使用 Databricks SQL 语句执行 API 和 EXTERNAL_LINKS 处置来检索大型数据集时,都遵循以下安全最佳做法:

  • 删除 Azure 存储请求的 Databricks 授权标头
  • 保护 SAS URL 和 SAS 令牌

可以根据请求通过创建支持案例来禁用 EXTERNAL_LINKS 处置。 请联系 Azure Databricks 帐户团队以提出申请。

删除 Azure 存储请求的 Databricks 授权标头

所有使用 curl 的对 Databricks SQL 语句执行 API 的调用都必须附带一个包含 Azure Databricks 访问凭据的 Authorization 标头。 每当从 Azure 存储下载数据时,请不要包含此 Authorization 标头。 此标头不是必需的,它可能会无意中透露你的 Azure Databricks 访问凭据。

保护 SAS URL 和 SAS 令牌

每当使用 EXTERNAL_LINKS 处置时,都会生成一个短期 SAS URL,调用方可以使用该 URL 通过 TLS 直接从 Azure 存储下载结果。 由于此 SAS URL 中嵌入了一个短期 SAS 令牌,因此应同时保护 SAS URL 和 SAS 令牌。