

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 建筑物 AWS Glue Data Catalog 视图
<a name="working-with-views"></a>

在中 AWS Glue Data Catalog，*视图*是一个虚拟表，其中的内容由引用一个或多个表的 SQL 查询定义。您可以使用 EMR Serverless 或 5.0 版本的 Amazon Athena、Amazon Redshift 或 Apache Spark 的 SQL 编辑器创建最多引用 10 个表的数据目录视图。 AWS Glue 视图的基础参考表可以属于同一个数据库，也可以属于同一 AWS 账户数据目录中的不同数据库。

您可以引用标准 AWS Glue 表和开放表格式 (OTF) 的表，例如 [Apache Hudi](https://hudi.incubator.apache.org/)、Linux Foundation D [elta Lak](https://delta.io/) e 和 [Apache Iceberg](https://iceberg.apache.org/)，底层数据存储在注册的 Amazon S3 位置中。 AWS Lake Formation此外，您还可以根据与 Lake Formation 共享的 Amazon Redshift 数据共享中的联合表创建视图。

## 将数据目录视图与其它视图类型区分开来
<a name="diff-views"></a>

数据目录视图与 Apache Hive、Apache Spark 和 Amazon Athena 视图不同。数据目录视图是的本机功能 AWS Glue Data Catalog，也是由多方言定义者创建的视图。您可以使用 Athena 或 Amazon Redshift Spectrum 等支持的分析服务之一创建数据目录视图，并使用其它支持的分析服务访问相同的视图。另一方面，Apache Hive、Apache Spark 和 Athena 视图是在 Athena 和 Amazon Redshift 等每个分析服务中独立创建的，并且仅在该服务中可见和可访问。

## 什么是定义者视图？
<a name="definer-view"></a>

 定义者视图是一种 SQL 视图，根据创建视图的主体的权限进行操作。定义者角色拥有访问所引用表的必要权限，并运行定义视图的 SQL 语句。定义者创建视图并通过精细 AWS Lake Formation的访问控制与其他用户共享。

当用户查询定义者视图时，查询引擎会使用定义者角色的权限访问底层引用表。这种方法使用户能够与视图交互，而无需直接访问源表，从而增强了安全性并简化了数据访问管理。

要设置定义者视图，定义者 IAM 角色可以与基表位于同一个 AWS 账户中，也可以使用跨账户定义者角色位于不同的账户中。有关定义者角色所需权限的更多信息，请参阅[创建视图的先决条件](views-prereqs.md)。

## 多方言视图框架
<a name="multi-dialect"></a>

数据目录支持使用多种结构化查询语言（SQL）方言创建视图。SQL 是一种用于在关系数据库中存储和处理信息的语言，每个 AWS 分析引擎都使用自己的 SQL 变体或 SQL 方言。

您可以使用一种支持的分析查询引擎，采用一种 SQL 方言创建数据目录视图。随后，您可以在任何其它支持的分析引擎中使用不同 SQL 方言的 `ALTER VIEW` 语句更新视图。不过，每种方言都必须引用一组相同的表、列和数据类型。

您可以使用 `GetTable` API AWS CLI 和 AWS 控制台访问视图可用的多种方言。因此，数据目录视图是可见的，可在支持的不同分析引擎中进行查询。

通过定义可从多个引擎查询的通用视图架构和元数据对象，数据目录视图使您能够在整个数据湖中使用统一视图。

有关如何为每种方言解析架构的更多详细信息，请参阅 [API 参考链接]()。有关不同类型的匹配规则的更多详细信息，请参阅 [API 文档中相关章节的链接]()。

## 整合 Lake Formation 权限
<a name="lf-view-integ"></a>

您可以使用 AWS Lake Formation 集中管理用户 AWS Glue Data Catalog 视图的权限。您可以使用命名的资源方法或 LF-Tag 授予对数据目录视图的精细权限，并在 AWS 组织和组织单位之间 AWS 账户共享这些权限。您还可以 AWS 区域 使用资源链接共享和访问数据目录视图。这样，用户就可以在不复制数据来源并共享底层表的情况下提供数据访问权限。

数据目录视图的 `CREATE VIEW` DDL 语句可以引用开放表格式 (OTF) 的标准 AWS Glue 表和表，例如 Hudi、Delta Lake 和 Iceberg，其基础数据存储在 Lake Formation 注册的 Amazon S3 位置，以及与 Lake Formation 共享的 Amazon Redshift 数据共享中的联合表。表可以是任何文件格式，只要用于查询视图的引擎支持该格式即可。您也可以引用运行引擎的内置函数，但可能不允许引用其它特定于引擎的资源。有关更多详细信息，请参阅 [数据目录视图注意事项和限制](views-notes.md)

## 使用案例
<a name="views-use-cases"></a>

以下是数据目录视图的重要使用案例：
+ 创建和管理对单个视图架构的权限。这有助于避免对在多个引擎中创建的重复视图的权限存在不一致的风险。
+ 向用户授予对引用多个表的视图的权限，而无需直接授予对基础引用表的权限。
+ 通过在视图上应用 LF 标签，并向用户授予基于 LF 标签的权限，使用 LF 标签在表上实现行级筛选（LF 标签只级联到列级别）。

## 支持的视图 AWS 分析服务
<a name="views-supported-engines"></a>

以下 AWS 分析服务支持创建数据目录视图：
+ Amazon Redshift
+ Amazon Athena 版本 3
+ Apache Spark on EMR Serverless
+  5.0 AWS Glue 版本上的 Apache Spark

## 其他资源
<a name="views-addtional-resources"></a>

您可以在本指南中了解有关数据目录的更多信息，也可以使用以下资源：

以下视频演示了如何从 Athena 和 Amazon Redshift 创建视图并进行查询。

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/rFO2OoxVYxE?si=Z0qsyuvTp2ZJg-PL/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/rFO2OoxVYxE?si=Z0qsyuvTp2ZJg-PL)


**Topics**
+ [将数据目录视图与其它视图类型区分开来](#diff-views)
+ [什么是定义者视图？](#definer-view)
+ [多方言视图框架](#multi-dialect)
+ [整合 Lake Formation 权限](#lf-view-integ)
+ [使用案例](#views-use-cases)
+ [支持的视图 AWS 分析服务](#views-supported-engines)
+ [其他资源](#views-addtional-resources)
+ [创建视图的先决条件](views-prereqs.md)
+ [使用 DDL 语句创建数据目录视图](create-views.md)
+ [使用创建数据目录视图 AWS Glue APIs](views-api-usage.md)
+ [授予对数据目录视图的权限](grant-perms-views.md)
+ [实体化视图](materialized-views.md)

# 创建视图的先决条件
<a name="views-prereqs"></a>
+ 要在数据目录中创建视图，您必须向 Lake Formation 注册引用表的基础 Amazon S3 数据位置。有关向 Lake Formation 注册数据的详细信息，请参阅[向数据湖添加 Amazon S3 位置](register-data-lake.md)。
+ 只有 IAM 角色可以创建数据目录视图。其他 IAM 身份无法创建数据目录视图。
+ 定义视图的 IAM 角色必须具有以下权限：
  + 对所有引用表（包括所有列）使用 `Grantable` 选项的 Lake Formation `SELECT` 权限。
  + 在要创建视图的目标数据库上，需要具备 Lake Formation `CREATE_TABLE` 权限。
  + Lake Formation 和 AWS Glue 服务机构承担该角色的信任政策。

------
#### [ JSON ]

****  

    ```
    {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "DataCatalogViewDefinerAssumeRole1",
                "Effect": "Allow",
                "Principal": {
                   "Service": [
                        "glue.amazonaws.com",
                        "lakeformation.amazonaws.com"
                     ]
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }
    ```

------
  + 目标： AWS Glue 和 Lake Formation 的PassRole 许可。

------
#### [ JSON ]

****  

    ```
    {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "DataCatalogViewDefinerPassRole1",
                "Action": [
                    "iam:PassRole"
                ],
                "Effect": "Allow",
                "Resource": "*",
                "Condition": {
                    "StringEquals": {
                        "iam:PassedToService": [ 
                            "glue.amazonaws.com",
                            "lakeformation.amazonaws.com"
                          ]
                    }
                }
            }
        ]
    }
    ```

------
  + AWS Glue 以及 Lake Formation 权限。

------
#### [ JSON ]

****  

    ```
    {
        "Version":"2012-10-17",		 	 	 
                     "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "Glue:GetDatabase",
                    "Glue:GetDatabases",
                    "Glue:CreateTable",
                    "Glue:GetTable",
                    "Glue:GetTables",
                    "Glue:BatchGetPartition",
                    "Glue:GetPartitions",
                    "Glue:GetPartition",
                    "Glue:GetTableVersion",
                    "Glue:GetTableVersions",
    				"Glue:PassConnection",
                    "lakeFormation:GetDataAccess"
                ],
                "Resource": "*"
            }
        ]   
    }
    ```

------
+ 不能在向 `IAMAllowedPrincipals` 组授予 `Super` 或 `ALL` 权限的数据库中创建视图。您可以撤销 `IAMAllowedPrincipals` 组对数据库的 `Super` 权限，请参阅[步骤 4：将数据存储切换到 Lake Formation 权限模型](upgrade-glue-lake-formation.md#upgrade-glue-lake-formation-step4)；也可以创建一个新数据库，在**新创建表的默认权限**下取消选中**仅对此数据库中的新表使用 IAM 访问控制**复选框。

# 使用 DDL 语句创建数据目录视图
<a name="create-views"></a>

你可以使用适用于 Athena 的 SQL 编辑器、Amazon Redshift 和使用/来创建 AWS Glue Data Catalog 视图。 AWS Glue APIs AWS CLI

要使用 SQL 编辑器创建数据目录视图，请选择 Athena 或 Redshift Spectrum，然后使用 `CREATE VIEW` 数据定义语言（DDL）语句创建视图。使用第一个引擎的方言创建视图后，可以使用第二个引擎的 `ALTER VIEW` DDL 语句添加其它方言。

在定义视图时，必须考虑以下几点：
+ **定义多方言视图** - 定义具有多种方言的视图时，不同方言的架构必须匹配。每种 SQL 方言的语法规范略有不同。在所有方言中，定义数据目录视图的查询语法应解析为完全相同的列列表，包括类型和名称。这些信息存储在视图的 `StorageDescriptor` 中。方言还必须引用数据目录中相同的底层表对象。

  要使用 DDL 向视图添加另一种方言，可以使用 `ALTER VIEW` 语句。如果 `ALTER VIEW` 语句试图更新视图定义，如修改视图的存储描述符或底层表，该语句就会出错，提示“输入与现有存储描述符不匹配”。您可以使用 SQL 转换操作来确保视图列类型匹配。
+ **更新视图** - 要更新视图，可以使用 `UpdateTable` API。如果在不匹配存储描述符或引用表的情况下更新视图，则可以提供 `FORCE` 标志（语法参见引擎 SQL 文档）。强制更新后，视图将采用强制的 `StorageDescriptor` 和引用表。任何进一步的 `ALTER VIEW` DDL 都应与修改后的值相匹配。已更新为具有不兼容方言的视图将处于“过时”状态。视图状态在 Lake Formation 控制台中可见，可使用 `GetTable` 操作查看。
+ **以字符串形式引用 varchar 列类型** – 无法将 Redshift Spectrum 的 varchar 列类型转换为字符串。如果在 Redshift Spectrum 中创建了具有 varchar 列类型的视图，而后续方言尝试将该字段作为字符串引用，则数据目录会将其作为字符串处理，而无需使用 `FORCE` 标志。
+ **复杂类型字段的处理** – Amazon Redshift 将所有复杂类型都视为 [SUPER 类型](https://docs.aws.amazon.com/redshift/latest/dg/r_SUPER_type.html)，而 Athena 则指定复杂类型。如果视图有一个 `SUPER` 类型字段，而另一个引擎将该列引用为特定的复杂类型，如 struct（`<street_address:struct<street_number:int, street_name:string, street_type:string>>`），那么数据目录会认为该字段是特定的复杂类型，并在存储描述符中使用该字段，而无需使用 `Force` 标志。

有关用于创建和管理数据目录视图的语法的更多信息，请参阅：
+ 《Amazon Athena 用户指南》中的[使用 AWS Glue Data Catalog 视图](https://docs.aws.amazon.com/athena/latest/ug/views-glue.html)。
+ 《Amazon Athena 用户指南》中的 [Glue Data Catalog 视图查询语法](https://docs.aws.amazon.com/athena/latest/ug/views-glue-ddl.html)。
+ 《Amazon Redshift 数据库开发人员指南》中的[在 AWS Glue Data Catalog中创建视图](https://docs.aws.amazon.com/redshift/latest/dg/data-catalog-views-overview.html)。

  有关与 Data Catalog 中的视图相关的 SQL 命令的更多信息，请参阅 [CREATE EXTERNAL VIEW](https://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_EXTERNAL_VIEW.html)、[ALTER EXTERNAL VIEW](https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_EXTERNAL_VIEW.html) 和 [DROP EXTERNAL VIEW](https://docs.aws.amazon.com/redshift/latest/dg/r_DROP_EXTERNAL_VIEW.html)。

创建数据目录视图后，该视图的详细信息可在 Lake Formation 控制台中查看。

1. 在 Lake Formation 控制台中选择“数据目录”下的**视图**。

1. 可用视图列表将显示在“视图”页面上。

1. 从列表中选择一个视图，详细信息页面将显示该视图的属性。

![\[下面的部分包含五个水平排列的选项卡，每个选项卡都包含相应的信息。\]](http://docs.aws.amazon.com/zh_cn/lake-formation/latest/dg/images/view-definition.png)


架构  
选择 `Column` 行，然后选择**编辑 LF 标签**，以更新标签值或分配新的 LF 标签。

SQL 定义  
您可以查看可用 SQL 定义的列表。选择**添加 SQL 定义**，然后选择要添加 SQL 定义的查询引擎。在 `Edit definition` 列下选择查询引擎（Athena 或 Amazon Redshift）以更新 SQL 定义。

LF 标签  
选择**编辑 LF 标签**以编辑标签的值或分配新标签。您可以使用 LF 标签来授予对视图的权限。

跨账户访问  
您可以看到与您共享数据目录视图的 AWS 账户组织和组织单位 (OUs) 的列表。

基础表  
用于创建视图的 SQL 定义中引用的基础表显示在此选项卡下。

# 使用创建数据目录视图 AWS Glue APIs
<a name="views-api-usage"></a>

您可以使用 AWS Glue [CreateTable](https://docs.aws.amazon.com/glue/latest/webapi/API_CreateTable.html)和[UpdateTable](https://docs.aws.amazon.com/glue/latest/webapi/API_UpdateTable.html) APIs 来创建和更新数据目录中的视图。`CreateTable` 和 `UpdateTable` 操作为 `ViewDefinition` 提供了新的 `TableInput` 结构，而 `SearchTables`、`GetTable`、`GetTables`、`GetTableVersion`、`GetTableVersions` 操作则在其视图输出语法中提供了 `ViewDefinition`。此外，`GetTable` API 输出中还有一个新的 `Status` 字段。

两个新 AWS Glue 连接可用于验证每个支持的查询引擎的 SQL 方言， Amazon Athena 以及 Amazon Redshift。

`CreateTable`与视图一起使用时 `UpdateTable` APIs ，和是异步的。当使用多个 SQL 方言调用 APIs 这些方言时，将使用每个引擎验证该调用，以确定该方言是否可以在该引擎上运行，以及每种方言的视图生成的架构是否匹配。该 AWS Glue 服务使用这些连接对分析引擎进行内部调用。这些调用模拟了在引擎上执行 `CREATE VIEW` 或 `ALTER VIEW` SQL DDL 时引擎的验证过程。

如果提供的 SQL 有效，且视图方言之间的架构匹配，则 AWS Glue API 会以原子方式提交结果。原子性允许在不停机的情况下创建或更改具有多种方言的视图。

**Topics**
+ [创建 AWS Glue 连接以验证状态](views-api-usage-connection.md)
+ [验证视图生成状态](views-api-usage-get-table.md)
+ [异步状态和操作](views-api-usage-async-states.md)
+ [查看异步操作期间的创建失败场景](views-api-usage-errors.md)

# 创建 AWS Glue 连接以验证状态
<a name="views-api-usage-connection"></a>

要使用或`UpdateTable`操作创建`CreateTable`或更新 AWS Glue Data Catalog 视图，必须创建一种用于验证的新 AWS Glue 连接类型，并将其提供给支持的分析引擎。要在 Athena 或 Amazon Redshift 中使用数据目录视图，需要这些连接。只能使用 AWS CLI AWS SDKs、或创建这些连接 AWS Glue APIs。您不能使用 AWS 管理控制台 来创建 AWS Glue 连接。

**注意**  
如果视图定义者角色和调用 `CreateTable` 或 `UpdateTable` 的角色不同，那么它们都需要在 IAM 策略声明中获得 `glue:PassConnection` 权限。

有关更多信息，请参阅[创建连接文档](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/glue/create-connection.html) AWS CLI 。

**AWS CLI 用于创建连接的命令**  
以下是用于创建连接的 AWS CLI 命令：

```
aws glue create-connection --region us-east-1 
--endpoint-url https://glue.us-east-1.amazonaws.com 
--cli-input-json file:///root/path/to/create-connection.json
```

**AWS CLI 输入 json**  
对于 Amazon Redshift：

```
{
    "CatalogId": "123456789012",
    "ConnectionInput": {
        "ConnectionType": "VIEW_VALIDATION_REDSHIFT",
        "Name": "views-preview-cluster-connection-2",
        "Description": "My first Amazon Redshift validation connection",
        "ConnectionProperties": {
            "DATABASE": "dev",
            "CLUSTER_IDENTIFIER": "glue-data-catalog-views-preview-cluster"
        }
    }
}
```

对于 Amazon Athena：

```
{
    "CatalogId": "123456789012",
    "ConnectionInput": {
        "ConnectionType": "VIEW_VALIDATION_ATHENA",
        "Name": "views-preview-cluster-connection-3",
        "Description": "My first Amazon Athena validation connection",
        "ConnectionProperties": {
            "WORKGROUP_NAME": "workgroup-name"
        }
    }
}
```

# 验证视图生成状态
<a name="views-api-usage-get-table"></a>

运行 `CreateTable` 或 `UpdateTable` 操作时，`GetTable` API 输出的 `Status` 字段会显示视图创建状态的详细信息。对于表尚不存在的`create`请求，在异步处理期间 AWS Glue 创建一个空表。调用 `GetTable` 时，可以传递一个可选的布尔标志 `IncludeStatusDetails`，用于显示请求的诊断信息。如果失败，此标志会显示一条错误消息，其中包含每种方言的个别状态。

视图创建、读取、更新和删除 (CRUD) 操作期间的错误可能发生在 AWS Glue/Lake Formation 服务中处理期间，或者在 Amazon Redshift 或 Athena 中进行视图 SQL 验证期间。当引擎在验证过程中发生错误时， AWS Glue 服务会提供引擎返回的错误信息。

**状态字段**  
以下是状态字段：
+ 状态：通用状态，与不同类型的作业无关：
  + QUEUED
  + 进行中
  + 成功
  + FAILED
+ Action – 表示对表调用了哪种操作，目前只有 `CREATE` 或 `UPDATE` 操作可用。

  在处理视图时，区分 `UPDATE` 和 `CREATE` 操作非常重要。操作类型决定了查询表的方式。

   `UPDATE` 操作表示表已存在于数据目录中。在这种情况下，您可以继续查询之前创建的表，不会出现任何问题。另一方面，`CREATE ` 操作表示该表以前从未成功创建过。如果将表标记为 `CREATE`，则尝试查询该表将失败，因为系统中还不存在该表。因此，在尝试查询表之前，必须确定操作类型（UPDATE 或 CREATE）。
+ RequestedBy — 请求异步更改的用户的 ARN。
+ UpdatedBy — 上次手动更改异步更改流程（例如请求取消或修改）的用户的 ARN。
+ Error – 此字段仅在状态为 **FAILED** 时出现。这是一条父级异常消息。每种方言可能存在不同的错误。
  + ErrorCode — 异常的类型。
  + ErrorMessage — 例外情况的简要描述。
+ RequestTime — 一个 ISO 8601 格式的日期字符串，表示启动更改的时间。
+ UpdateTime — 一个 ISO 8601 格式的日期字符串，表示上次更新状态的时间。

# 异步状态和操作
<a name="views-api-usage-async-states"></a>

当您运行 `glue:CreateTable` 请求时，将开始异步创建数据目录视图。在以下各节中，本文档描述了`glue:GetTable`响应中可用的 AWS Glue 视图。`Status`为简洁起见，本节略去完整响应。

```
{
    "Table": {
        ...
        "Status": {
            ...
            "Action": "CREATE",
            "State": "QUEUED",
        }
    }
}
```

上述两个属性均代表重要的诊断信息，这些信息指示异步操作的状态，以及可对此视图执行的操作。以下是这些属性的可能值。

1. `Status.Action`

   1. CREATE

   1. UPDATE

1. `Status.State`

   1. QUEUED

   1. 进行中

   1. 成功

   1. FAILED

还需要注意的是，数据目录视图上的某些更新不需要异步操作。例如，用户可能希望更新表的 `Description` 属性。由于这不需要任何异步操作，因此生成的表元数据将没有任何 `Status`，属性将为 `NULL`。

```
{
    "Table": {
        ...,
        "Description": "I changed this attribute!"
    }
}
```

接下来，本主题探讨上述状态信息如何影响可以对 AWS Glue 视图执行的操作。

**胶水：CreateTable**  
与任何 Glue 表的 `glue:CreateTable` 功能相比，该 API 没有任何变化。可以为任何尚未存在的表名调用 `CreateTable`。

**胶水：UpdateTable**  
无法对具有以下状态信息的 AWS Glue 视图执行此操作：

1. Action == CREATE and State == QUEUED

1. Action == CREATE and State == IN\$1PROGRESS

1. Action == CREATE and state == FAILED

1. Action == UPDATE and state == QUEUED

1. Action == UPDATE and state == IN\$1PROGRESS

总之，只有当数据目录视图满足以下要求时，才能更新该视图。

1. 首次成功创建。

   1. Action == CREATE and State == SUCCESS

1. 在异步更新操作后达到终端状态。

   1. Action == UPDATE and State == SUCCESS

   1. Action == UPDATE and State == FAILED

1. 由于同步更新，状态属性为 `NULL`。

**胶水：DeleteTable**  
与任何 AWS Glue 表的运行方式`glue:DeleteTable`相比，此操作没有任何变化。无论数据目录视图处于何种状态，都可以删除该视图。

**胶水：GetTable**  
与任何 AWS Glue 表的运行方式`glue:GetTable`相比，此操作没有任何变化。但是，在首次成功创建数据目录视图之前，不能从分析引擎中查询该视图。`Action == CREATE and State == SUCCESS`。首次成功创建数据目录视图后，无论其状态如何，都可以查询该视图。

**注意**  
本节中的所有信息都适用于读取的所有表`GetTable`， APIs 例如`GetTables`、和`SearchTables`。

# 查看异步操作期间的创建失败场景
<a name="views-api-usage-errors"></a>

以下示例代表了 `CreateTable` 或 `UpdateTable` 视图 API 调用可能导致的错误类型。由于 SQL 查询失败的错误范围相当大，因此这些错误并不详尽。

## 场景 1：Amazon Redshift 查询失败
<a name="views-api-usage-errors-scenario-1"></a>

为 Amazon Redshift 提供的查询包含一个拼写错误的表名，在验证过程中无法在数据目录中找到。由此产生的错误会显示在视图的 `GetTable` 响应的 `Status` 字段中。

`GetTable` 请求：

```
{
    "CatalogId": "123456789012",
    "DatabaseName": "async-view-test-db",
    "TableInput": {
        "Name": "view-athena-redshift-72",
        "Description": "This is an atomic operation",
        "StorageDescriptor": {
            "Columns": [
                { "Name": "col1", "Type": "int" },
                { "Name": "col2", "Type": "string" },
                { "Name": "col3", "Type": "double" }
            ]
        },
        "ViewDefinition": {
            "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
            "SubObjects": [ "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1" ],
            "Representations": [
                {
                    "Dialect": "ATHENA",
                    "DialectVersion": "3",
                    "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                    "ValidationConnection": "athena-connection"
                },
                {
                    "Dialect": "REDSHIFT",
                    "DialectVersion": "1.0",
                    "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table__1\";",
                    "ValidationConnection": "redshift-connection"
                }
            ]
        }
    }
}
```

`GetTable` 响应：

```
IncludeStatusDetails = FALSE
{
    "Table": {
        "Name": "view-athena-redshift-72",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:39:19-07:00",
        "UpdateTime": "2024-07-11T11:39:19-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:39:19-07:00",
            "UpdateTime": "2024-07-11T11:40:06-07:00",
            "Action": "CREATE",
            "State": "FAILED"
        }
    }
}

IncludeStatusDetails = TRUE
{
    "Table": {
        "Name": "view-athena-redshift-72",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:39:19-07:00",
        "UpdateTime": "2024-07-11T11:39:19-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:39:19-07:00",
            "UpdateTime": "2024-07-11T11:40:06-07:00",
            "Action": "CREATE",
            "State": "FAILED",
            "Error": {
                "ErrorCode": "QueryExecutionException",
                "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: redshift-connection | Query Execution Id: ddb711d3-2415-4aa9-b251-6a76ab4f41b1 | Timestamp: Thu Jul 11 18:39:37 UTC 2024]: Redshift returned error for the statement: ERROR: AwsClientException: EntityNotFoundException from glue - Entity Not Found"
            },
            "Details": {
                "RequestedChange": {
                    "Name": "view-athena-redshift-72",
                    "DatabaseName": "async-view-test-db",
                    "Description": "This is an atomic operation",
                    "Retention": 0,
                    "StorageDescriptor": {
                        "Columns": [
                            {
                                "Name": "col1",
                                "Type": "int"
                            },
                            {
                                "Name": "col2",
                                "Type": "string"
                            },
                            {
                                "Name": "col3",
                                "Type": "double"
                            }
                        ],
                        "Compressed": false,
                        "NumberOfBuckets": 0,
                        "SortColumns": [],
                        "StoredAsSubDirectories": false
                    },
                    "TableType": "VIRTUAL_VIEW",
                    "IsRegisteredWithLakeFormation": false,
                    "CatalogId": "123456789012",
                    "IsRowFilteringEnabled": false,
                    "VersionId": "-1",
                    "DatabaseId": "<databaseID>",
                    "ViewDefinition": {
                        "IsProtected": true,
                        "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
                        "SubObjects": [
                            "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1"
                        ],
                        "Representations": [
                            {
                                "Dialect": "ATHENA",
                                "DialectVersion": "3",
                                "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                                "IsStale": false
                            },
                            {
                                "Dialect": "REDSHIFT",
                                "DialectVersion": "1.0",
                                "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table__1\";",
                                "IsStale": false
                            }
                        ]
                    },
                    "IsMultiDialectView": true
                },
                "ViewValidations": [
                    {
                        "Dialect": "ATHENA",
                        "DialectVersion": "3",
                        "ViewValidationText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                        "UpdateTime": "2024-07-11T11:40:06-07:00",
                        "State": "SUCCESS"
                    },
                    {
                        "Dialect": "REDSHIFT",
                        "DialectVersion": "1.0",
                        "ViewValidationText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table__1\";",
                        "UpdateTime": "2024-07-11T11:39:37-07:00",
                        "State": "FAILED",
                        "Error": {
                            "ErrorCode": "QueryExecutionException",
                            "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: redshift-connection | Query Execution Id: ddb711d3-2415-4aa9-b251-6a76ab4f41b1 | Timestamp: Thu
 Jul 11 18:39:37 UTC 2024]: Redshift returned error for the statement: ERROR: AwsClientException: EntityNotFoundException from glue - Entity Not Found"
                        }
                    }
                ]
            }
        }
    }
}
```

## 场景 2：Amazon Redshift 连接无效
<a name="views-api-usage-errors-scenario-2"></a>

以下示例中的 Amazon Redshift 连接格式不正确，因为它引用了提供的终端节点中不存在的亚马逊 Redshift 数据库。 cluster/serverless Amazon Redshift 无法验证视图，来自 Amazon Redshift 的 `GetTable` 响应中的 `Status` 字段显示错误（`"State": "FAILED"`）。

`GetTable` 请求：

```
{
    "CatalogId": "123456789012",
    "DatabaseName": "async-view-test-db",
    "TableInput": {
        "Name": "view-athena-redshift-73",
        "Description": "This is an atomic operation",
        "StorageDescriptor": {
            "Columns": [
                { "Name": "col1", "Type": "int" },
                { "Name": "col2", "Type": "string" },
                { "Name": "col3", "Type": "double" }
            ]
        },
        "ViewDefinition": {
            "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
            "SubObjects": [ "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1" ],
            "Representations": [
                {
                    "Dialect": "ATHENA",
                    "DialectVersion": "3",
                    "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                    "ValidationConnection": "athena-connection"
                },
                {
                    "Dialect": "REDSHIFT",
                    "DialectVersion": "1.0",
                    "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                    "ValidationConnection": "redshift-connection-malformed"
                }
            ]
        }
    }
}
```

`GetTable` 响应：

```
IncludeStatusDetails = FALSE
{
    "Table": {
        "Name": "view-athena-redshift-73",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:43:27-07:00",
        "UpdateTime": "2024-07-11T11:43:27-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:43:27-07:00",
            "UpdateTime": "2024-07-11T11:43:40-07:00",
            "Action": "CREATE",
            "State": "FAILED"
        }
    }
}

IncludeStatusDetails = TRUE
{
    "Table": {
        "Name": "view-athena-redshift-73",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:43:27-07:00",
        "UpdateTime": "2024-07-11T11:43:27-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:43:27-07:00",
            "UpdateTime": "2024-07-11T11:43:40-07:00",
            "Action": "CREATE",
            "State": "FAILED",
            "Error": {
                "ErrorCode": "QueryExecutionException",
                "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: redshift-connection-malformed | Query Execution Id: 69bfafd4-3d51-4cb0-9320-7ce5404b1809 | Timestamp: Thu Jul 11 18:43:38 UTC 2024]: Redshift returned error for the statement: FATAL: database \"devooo\" does not exist"
            },
            "Details": {
                "RequestedChange": {
                    "Name": "view-athena-redshift-73",
                    "DatabaseName": "async-view-test-db",
                    "Description": "This is an atomic operation",
                    "Retention": 0,
                    "StorageDescriptor": {
                        "Columns": [
                            {
                                "Name": "col1",
                                "Type": "int"
                            },
                            {
                                "Name": "col2",
                                "Type": "string"
                            },
                            {
                                "Name": "col3",
                                "Type": "double"
                            }
                        ],
                        "Compressed": false,
                        "NumberOfBuckets": 0,
                        "SortColumns": [],
                        "StoredAsSubDirectories": false
                    },
                    "TableType": "VIRTUAL_VIEW",
                    "IsRegisteredWithLakeFormation": false,
                    "CatalogId": "123456789012",
                    "IsRowFilteringEnabled": false,
                    "VersionId": "-1",
                    "DatabaseId": "<databaseID>",
                    "ViewDefinition": {
                        "IsProtected": true,
                        "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
                        "SubObjects": [
                            "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1"
                        ],
                        "Representations": [
                            {
                                "Dialect": "ATHENA",
                                "DialectVersion": "3",
                                "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                                "IsStale": false
                            },
                            {
                                "Dialect": "REDSHIFT",
                                "DialectVersion": "1.0",
                                "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                                "IsStale": false
                            }
                        ]
                    },
                    "IsMultiDialectView": true
                },
                "ViewValidations": [
                    {
                        "Dialect": "ATHENA",
                        "DialectVersion": "3",
                        "ViewValidationText": "SELECT * FROM \"gdc-view-playground-db\".\"table_1\"",
                        "UpdateTime": "2024-07-11T11:43:40-07:00",
                        "State": "SUCCESS"
                    },
                    {
                        "Dialect": "REDSHIFT",
                        "DialectVersion": "1.0",
                        "ViewValidationText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                        "UpdateTime": "2024-07-11T11:43:38-07:00",
                        "State": "FAILED",
                        "Error": {
                            "ErrorCode": "QueryExecutionException",
                            "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: redshift-connection-malformed | Query Execution Id: 69bfafd4-3d51-4cb0-9320-7ce5404b1809 | Time
stamp: Thu Jul 11 18:43:38 UTC 2024]: Redshift returned error for the statement: FATAL: database \"devooo\" does not exist"
                        }
                    }
                ]
            }
        }
    }
}
```

## 场景 3：Athena 查询失败
<a name="views-api-usage-errors-scenario-3"></a>

此处 Athena 的 SQL 无效，因为查询拼错了数据库名称。Athena 查询验证会捕捉到这一点，由此产生的错误会通过 `GetTable` 调用中的 `Status` 对象显示出来。

`GetTable` 请求：

```
{
    "CatalogId": "123456789012",
    "DatabaseName": "async-view-test-db",
    "TableInput": {
        "Name": "view-athena-redshift-70",
        "Description": "This is an atomic operation",
        "StorageDescriptor": {
            "Columns": [
                { "Name": "col1", "Type": "int" },
                { "Name": "col2", "Type": "string" },
                { "Name": "col3", "Type": "double" }
            ]
        },
        "ViewDefinition": {
            "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
            "SubObjects": [ "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1" ],
            "Representations": [
                {
                    "Dialect": "ATHENA",
                    "DialectVersion": "3",
                    "ViewOriginalText": "SELECT * FROM \"gdc--view-playground-db\".\"table_1\"",
                    "ValidationConnection": "athena-connection"
                },
                {
                    "Dialect": "REDSHIFT",
                    "DialectVersion": "1.0",
                    "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                    "ValidationConnection": "redshift-connection"
                }
            ]
        }
    }
}
```

`GetTable` 响应：

```
IncludeStatusDetails = FALSE
{
    "Table": {
        "Name": "view-athena-redshift-70",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:09:53-07:00",
        "UpdateTime": "2024-07-11T11:09:53-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:09:54-07:00",
            "UpdateTime": "2024-07-11T11:10:41-07:00",
            "Action": "CREATE",
            "State": "FAILED",
        }
    }
}

IncludeStatusDetails = TRUE
{
    "Table": {
        "Name": "view-athena-redshift-70",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:09:53-07:00",
        "UpdateTime": "2024-07-11T11:09:53-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:09:54-07:00",
            "UpdateTime": "2024-07-11T11:10:41-07:00",
            "Action": "CREATE",
            "State": "FAILED",
            "Error": {
                "ErrorCode": "QueryExecutionException",
                "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: athena-connection | Query Execution Id: d9bb1e6d-ce26-4b35-8276-8a199af966aa | Timestamp: Thu Jul 11 18:10:
41 UTC 2024]: Athena validation FAILED: {ErrorCategory: 2,ErrorType: 1301,Retryable: false,ErrorMessage: line 1:118: Schema 'gdc--view-playground-db' does not exist}"
            },
            "Details": {
                "RequestedChange": {
                    "Name": "view-athena-redshift-70",
                    "DatabaseName": "async-view-test-db",
                    "Description": "This is an atomic operation",
                    "Retention": 0,
                    "StorageDescriptor": {
                        "Columns": [
                            {
                                "Name": "col1",
                                "Type": "int"
                            },
                            {
                                "Name": "col2",
                                "Type": "string"
                            },
                            {
                                "Name": "col3",
                                "Type": "double"
                            }
                        ],
                        "Compressed": false,
                        "NumberOfBuckets": 0,
                        "SortColumns": [],
                        "StoredAsSubDirectories": false
                    },
                    "TableType": "VIRTUAL_VIEW",
                    "IsRegisteredWithLakeFormation": false,
                    "CatalogId": "123456789012",
                    "IsRowFilteringEnabled": false,
                    "VersionId": "-1",
                    "DatabaseId": "<databaseID>",
                    "ViewDefinition": {
                        "IsProtected": true,
                        "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
                        "SubObjects": [
                            "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1"
                        ],
                        "Representations": [
                            {
                                "Dialect": "ATHENA",
                                "DialectVersion": "3",
                                "ViewOriginalText": "SELECT * FROM \"gdc--view-playground-db\".\"table_1\"",
                                "IsStale": false
                            },
                            {
                                "Dialect": "REDSHIFT",
                                "DialectVersion": "1.0",
                                "ViewOriginalText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                                "IsStale": false
                            }
                        ]
                    },
                    "IsMultiDialectView": true
                },
                "ViewValidations": [
                    {
                        "Dialect": "ATHENA",
                        "DialectVersion": "3",
                        "ViewValidationText": "SELECT * FROM \"gdc--view-playground-db\".\"table_1\"",
                        "UpdateTime": "2024-07-11T11:10:41-07:00",
                        "State": "FAILED",
                        "Error": {
                            "ErrorCode": "QueryExecutionException",
                            "ErrorMessage": "Error received during view SQL validation using a connection: [Connection Name: athena-connection | Query Execution Id: d9bb1e6d-ce26-4b35-8276-8a199af966aa | Timestamp: Thu J
ul 11 18:10:41 UTC 2024]: Athena validation FAILED: {ErrorCategory: 2,ErrorType: 1301,Retryable: false,ErrorMessage: line 1:118: Schema 'gdc--view-playground-db' does not exist}"
                        }
                    },
                    {
                        "Dialect": "REDSHIFT",
                        "DialectVersion": "1.0",
                        "ViewValidationText": "SELECT * FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                        "UpdateTime": "2024-07-11T11:10:41-07:00",
                        "State": "SUCCESS"
                    }
                ]
            }
        }
    }
}
```

## 场景 4：存储描述符不匹配
<a name="views-api-usage-errors-scenario-4"></a>

为 Athena 方言提供的 SQL 选择 `col1` 和 `col2`，而为 Redshift 提供的 SQL 只选择 `col1`。这会导致存储描述符不匹配错误。

`GetTable` 请求：

```
{
    "CatalogId": "123456789012",
    "DatabaseName": "async-view-test-db",
    "TableInput": {
        "Name": "view-athena-redshift-71",
        "Description": "This is an atomic operation",
        "StorageDescriptor": {
            "Columns": [
                { "Name": "col1", "Type": "int" },
                { "Name": "col2", "Type": "string" },
                { "Name": "col3", "Type": "double" }
            ]
        },
        "ViewDefinition": {
            "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
            "SubObjects": [ "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1" ],
            "Representations": [
                {
                    "Dialect": "ATHENA",
                    "DialectVersion": "3",
                    "ViewOriginalText": "SELECT col1, col2 FROM \"gdc-view-playground-db\".\"table_1\"",
                    "ValidationConnection": "athena-connection"
                },
                {
                    "Dialect": "REDSHIFT",
                    "DialectVersion": "1.0",
                    "ViewOriginalText": "SELECT col1 FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                    "ValidationConnection": "redshift-connection"
                }
            ]
        }
    }
}
```

`GetTable` 响应：

```
IncludeStatusDetails = FALSE

{
    "Table": {
        "Name": "view-athena-redshift-71",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:22:02-07:00",
        "UpdateTime": "2024-07-11T11:22:02-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:22:02-07:00",
            "UpdateTime": "2024-07-11T11:23:19-07:00",
            "Action": "CREATE",
            "State": "FAILED"
        }
    }
}

IncludeStatusDetails = TRUE

{
    "Table": {
        "Name": "view-athena-redshift-71",
        "DatabaseName": "async-view-test-db",
        "Description": "",
        "CreateTime": "2024-07-11T11:22:02-07:00",
        "UpdateTime": "2024-07-11T11:22:02-07:00",
        "Retention": 0,
        "ViewOriginalText": "",
        "ViewExpandedText": "",
        "TableType": "",
        "CreatedBy": "arn:aws:iam::123456789012:user/zcaisse",
        "IsRegisteredWithLakeFormation": false,
        "CatalogId": "123456789012",
        "IsRowFilteringEnabled": false,
        "VersionId": "-1",
        "DatabaseId": "<databaseID>",
        "IsMultiDialectView": false,
        "Status": {
            "RequestedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "UpdatedBy": "arn:aws:iam::123456789012:user/zcaisse",
            "RequestTime": "2024-07-11T11:22:02-07:00",
            "UpdateTime": "2024-07-11T11:23:19-07:00",
            "Action": "CREATE",
            "State": "FAILED",
            "Error": {
                "ErrorCode": "InvalidInputException",
                "ErrorMessage": "Engine and existing storage descriptor mismatch"
            },
            "Details": {
                "RequestedChange": {
                    "Name": "view-athena-redshift-71",
                    "DatabaseName": "async-view-test-db",
                    "Description": "This is an atomic operation",
                    "Retention": 0,
                    "StorageDescriptor": {
                        "Columns": [
                            {
                                "Name": "col1",
                                "Type": "int"
                            },
                            {
                                "Name": "col2",
                                "Type": "string"
                            },
                            {
                                "Name": "col3",
                                "Type": "double"
                            }
                        ],
                        "Compressed": false,
                        "NumberOfBuckets": 0,
                        "SortColumns": [],
                        "StoredAsSubDirectories": false
                    },
                    "TableType": "VIRTUAL_VIEW",
                    "IsRegisteredWithLakeFormation": false,
                    "CatalogId": "123456789012",
                    "IsRowFilteringEnabled": false,
                    "VersionId": "-1",
                    "DatabaseId": "<databaseID>",
                    "ViewDefinition": {
                        "IsProtected": true,
                        "Definer": "arn:aws:iam::123456789012:role/GDCViewDefiner",
                        "SubObjects": [
                            "arn:aws:glue:us-east-1:123456789012:table/gdc-view-playground-db/table_1"
                        ],
                        "Representations": [
                            {
                                "Dialect": "ATHENA",
                                "DialectVersion": "3",
                                "ViewOriginalText": "SELECT col1, col2 FROM \"gdc-view-playground-db\".\"table_1\"",
                                "IsStale": false
                            },
                            {
                                "Dialect": "REDSHIFT",
                                "DialectVersion": "1.0",
                                "ViewOriginalText": "SELECT col1 FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                                "IsStale": false
                            }
                        ]
                    },
                    "IsMultiDialectView": true
                },
                "ViewValidations": [
                    {
                        "Dialect": "ATHENA",
                        "DialectVersion": "3",
                        "ViewValidationText": "SELECT col1, col2 FROM \"gdc-view-playground-db\".\"table_1\"",
                        "UpdateTime": "2024-07-11T11:23:19-07:00",
                        "State": "FAILED",
                        "Error": {
                            "ErrorCode": "InvalidInputException",
                            "ErrorMessage": "Engine and existing storage descriptor mismatch"
                        }
                    },
                    {
                        "Dialect": "REDSHIFT",
                        "DialectVersion": "1.0",
                        "ViewValidationText": "SELECT col1 FROM \"gdc-view-playground-external-schema\".\"table_1\";",
                        "UpdateTime": "2024-07-11T11:22:49-07:00",
                        "State": "FAILED",
                        "Error": {
                            "ErrorCode": "InvalidInputException",
                            "ErrorMessage": "Engine and existing storage descriptor mismatch"
                        }
                    }
                ]
            }
        }
    }
}
```

# 授予对数据目录视图的权限
<a name="grant-perms-views"></a>

 在中创建视图后 AWS Glue Data Catalog，您可以向各组织和组织单位的委托人授予视图的数据湖权限。 AWS 账户您可以使用 LF 标签或命名资源方法授予权限。有关标记资源的更多信息，请参阅 [Lake Formation 基于标签的访问控制](tag-based-access-control.md)。有关直接授予视图权限的更多信息，请参阅[使用命名资源方法授予对视图的权限](granting-view-permissions.md)。

# 实体化视图
<a name="materialized-views"></a>

**Topics**
+ [将实例化视图与其他视图类型区分开来](#materialized-views-differentiating)
+ [使用案例](#materialized-views-use-cases)
+ [重要概念](#materialized-views-key-concepts)
+ [实体化视图的权限](#materialized-views-permissions)
+ [创建和管理物化视图](#materialized-views-creating-managing)
+ [存储和数据访问](#materialized-views-storage-access)
+ [与 AWS Lake Formation 权限集成](#materialized-views-lake-formation)
+ [监控和调试](#materialized-views-monitoring-debugging)
+ [管理刷新作业](#materialized-views-managing-refresh-jobs)
+ [监控和排查](#materialized-views-monitoring-troubleshooting)
+ [注意事项和限制](#materialized-views-considerations-limitations)

在 AWS Glue 数据目录中，物化视图是一个托管表，它以 Apache Iceberg 格式存储预先计算的 SQL 查询结果。与每次访问时都执行查询的标准数据目录视图不同，物化视图会物理存储查询结果，并在基础源表更改时对其进行更新。你可以在亚马逊 Athena、亚马逊 EMR 或中使用 Apache Spark 3.5.6\$1 版本创建物化视图。 AWS Glue

物化视图引用了在 AWS Glue 数据目录中注册的 Apache Iceberg 表，预先计算的数据以 Apache Iceberg 表的形式存储在 Amazon S3 表存储桶或 Amazon S3 通用存储桶中，因此可以从包括亚马逊雅典娜、Amazon Redshift 和第三方冰山兼容引擎在内的多个查询引擎进行访问。

## 将实例化视图与其他视图类型区分开来
<a name="materialized-views-differentiating"></a>

物化视图在根本上不同于 AWS Glue 数据目录视图、Apache Spark 视图和 Amazon Athena 视图。虽然数据目录视图是虚拟表，每次访问时都会执行 SQL 查询定义，但物化视图会物理存储预先计算的查询结果。这消除了冗余计算，并显著提高了经常访问的复杂转换的查询性能。

物化视图还不同于使用 AWS Glue ETL 或自定义 Spark 作业构建的传统数据转换管道。您可以使用标准 SQL 语法定义物化视图，而不是编写自定义代码来处理变更检测、增量更新和工作流程编排。 AWS Glue 数据目录使用完全托管的计算基础架构自动监控源表、检测更改并刷新实体化视图。

## 使用案例
<a name="materialized-views-use-cases"></a>

以下是物化视图的重要用例：
+ **加速复杂的分析查询**-创建预先计算昂贵的联接、聚合和窗口函数的物化视图。Spark 引擎会自动重写后续查询以使用预先计算的结果，从而减少查询延迟和计算成本。
+ **简化数据转换管道** — 将处理变更检测、增量更新和工作流程编排的复杂 ETL 作业替换为基于 SQL 的简单物化视图定义。 AWS Glue 数据目录自动管理所有操作的复杂性。
+ 通过@@ **受管控的数据访问实现自助式分析** — 创建精选的物化视图，将原始数据转换为业务就绪型数据集。允许用户在不暴露底层源表的情况下访问物化视图，从而简化安全管理，同时支持自助分析。
+ **优化机器学习的特征工程**-定义实现机器学习模型特征转换的物化视图。自动刷新功能可确保功能存储在源数据演变时保持最新状态，而增量刷新可最大限度地降低计算成本。
+ **实现高效的数据共享**-创建物化视图，筛选和转换特定使用者的数据。使用跨账户和区域共享实体化视图 AWS Lake Formation，无需重复数据，同时保持集中化治理。

## 重要概念
<a name="materialized-views-key-concepts"></a>

### 自动刷新
<a name="materialized-views-automatic-refresh"></a>

自动刷新是一种持续监视源表并根据您定义的计划更新实体化视图的功能。创建物化视图时，您可以使用基于时间的调度来指定刷新频率，间隔频率可达一小时。 AWS Glue 数据目录使用托管 Spark 计算基础架构在后台执行刷新操作，透明地处理变更检测和增量更新的各个方面。

当源数据在刷新间隔之间发生变化时，实例化视图会暂时失效。在下一次定时刷新完成之前，直接访问物化视图的查询可能会返回过时的结果。对于需要立即访问最新数据的场景，可以使用 `REFRESH MATERIALIZED VIEW` SQL 命令执行手动刷新。

### 增量刷新
<a name="materialized-views-incremental-refresh"></a>

增量刷新是一种优化技术，它仅处理自上次刷新以来源表中已更改的数据，而不是重新计算整个实例化视图。 AWS Glue 数据目录利用 Apache Iceberg 的元数据层来有效地跟踪源表中的变化，并确定物化视图的哪些部分需要更新。

与完全刷新操作相比，这种方法可以显著降低计算成本和刷新持续时间，特别是对于大型数据集，在刷新周期之间，只有一小部分数据会发生变化。增量刷新机制会自动运行；您无需编写自定义逻辑即可检测或处理更改的数据。

### 自动查询重写
<a name="materialized-views-automatic-query-rewrite"></a>

自动查询重写是 Amazon Athena、Amazon EMR 和 Spark 引擎中提供的查询优化功能。 AWS Glue当您对基表执行查询时，Spark 优化器会分析您的查询计划并自动确定可用的物化视图能否更有效地满足查询。如果存在合适的实例化视图，则优化器会透明地重写查询，以使用预先计算的结果，而不是处理基表。

这种优化无需对您的应用程序代码或查询语句进行任何更改。Spark 优化器可确保自动查询重写仅在物化视图为最新视图并且可以生成准确结果时才适用。如果物化视图已过时或与查询要求不完全匹配，则优化程序会对基表执行原始查询计划，将正确性置于性能之上。

### 视图定义者角色
<a name="materialized-views-view-definer-role"></a>

物化视图基于创建该视图的 IAM 角色（称为视图定义者角色）的权限进行操作。定义者角色必须对实例化视图定义中引用的所有基表具有读取权限，并且必须对目标数据库具有创建表权限。当 AWS Glue 数据目录刷新实例化视图时，它将扮演定义者的角色来访问源表并写入更新的结果。

使用此安全模型，您可以向用户授予对实例化视图的访问权限，而无需授予他们对基础源表的直接权限。如果视图定义者角色失去对任何基表的访问权限，则在恢复权限之前，后续的刷新操作将失败。

## 实体化视图的权限
<a name="materialized-views-permissions"></a>

要创建和管理物化视图，必须配置 AWS Lake Formation 权限。创建实体化视图的 IAM 角色（定义者角色）需要对源表和目标数据库的特定权限。

### 定义者角色所需的权限
<a name="materialized-views-required-permissions-definer-role"></a>

定义者角色必须具有以下 Lake Formation 权限：
+ 在源表上 – 不带行、列或单元格筛选条件的 SELECT 或 ALL 权限
+ 在目标数据库上 – CREATE\$1TABLE 权限
+ 在 AWS Glue 数据目录上 — GetTable 以及 CreateTable API 权限

创建实体化视图时，定义者角色的 ARN 存储在视图定义中。执行自动刷新操作时， AWS Glue 数据目录将扮演此角色。如果定义者角色失去对源表的访问权限，则在恢复权限之前，刷新操作将失败。

### AWS Glue 任务的 IAM 权限
<a name="materialized-views-iam-permissions-glue-jobs"></a>

您的 AWS Glue 任务的 IAM 角色需要以下权限：

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetCatalog",
                "glue:GetCatalogs",
                "glue:GetTable",
                "glue:GetTables",
                "glue:CreateTable",
                "glue:UpdateTable",
                "glue:DeleteTable",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "cloudwatch:PutMetricData"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*:/aws-glue/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "lakeformation:GetDataAccess"
            ],
            "Resource": "*"
        }
    ]
}
```

用于物化视图自动刷新的角色必须对该角色具有 iam: PassRole 权限。

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:PassRole"
      ],
      "Resource": [
        "arn:aws:iam::111122223333:role/materialized-view-role-name"
      ]
    }
  ]
}
```

要让 Glue 自动刷新实体化视图，角色还必须具有以下信任策略，进而确保服务能够担任该角色。

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "glue.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

如果实体化视图存储在 S3 表类数据存储服务存储桶中，则还需要为角色添加以下权限。

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3tables:PutTableMaintenanceConfiguration"
      ],
      "Resource": "arn:aws:s3tables:*:123456789012:*"
    }
  ]
}
```

### 授予对实体化视图的访问权限
<a name="materialized-views-granting-access"></a>

要向其他用户授予查询物化视图的访问权限，请使用授予 AWS Lake Formation 对物化视图表的 SELECT 权限。用户无需直接访问基础源表即可查询实体化视图。

有关配置 Lake Formation 权限的详细信息，请参阅 AWS Lake Formation 开发人员指南中的授予和撤消数据目录资源的权限。

## 创建和管理物化视图
<a name="materialized-views-creating-managing"></a>

您可以在 Spark 引擎中使用 `CREATE MATERIALIZED VIEW` SQL 语句创建实例化视图。视图定义指定了定义转换逻辑、目标数据库和表名以及可选刷新配置的 SQL 查询。您可以定义复杂的转换，包括聚合、跨多个表的联接、筛选器和窗口函数。

```
CREATE MATERIALIZED VIEW sales_summary
AS
SELECT 
    region,
    product_category,
    SUM(sales_amount) as total_sales,
    COUNT(DISTINCT customer_id) as unique_customers
FROM sales_transactions
WHERE transaction_date >= current_date - interval '90' day
GROUP BY region, product_category;
```

要配置自动刷新，请在视图定义中包括刷新计划：

```
CREATE MATERIALIZED VIEW sales_summary
SCHEDULE REFRESH EVERY 1 HOUR
AS
SELECT region, product_category, SUM(sales_amount) as total_sales
FROM sales_transactions
GROUP BY region, product_category;
```

您可以使用以下`REFRESH MATERIALIZED VIEW`命令随时手动刷新实例化视图：

```
REFRESH MATERIALIZED VIEW sales_summary;
```

要修改现有实例化视图的刷新计划，请使用以下`ALTER MATERIALIZED VIEW`语句：

```
ALTER MATERIALIZED VIEW sales_summary
ADD SCHEDULE REFRESH EVERY 2 HOURS;
```

### 嵌套实体化视图
<a name="materialized-views-nested"></a>

您可以创建引用其他实例化视图作为基表的实例化视图，从而实现多阶段数据转换。创建嵌套实例化视图时， AWS Glue 数据目录会跟踪依赖关系并自动通过物化视图层次结构传播更新。当基础物化视图刷新时，所有依赖该视图的下游物化视图都会相应更新。

此功能允许您将复杂的转换分解为逻辑阶段，从而提高可维护性，并允许根据数据新鲜度要求选择性刷新转换层。

## 存储和数据访问
<a name="materialized-views-storage-access"></a>

物化视图将预先计算的结果存储为 Apache Iceberg 表存储在 S3 表存储桶中，或者将您的账户中的通用 S3 存储桶存储为通用的 S3 存储桶。 AWS AWS Glue 数据目录通过 S3 表的自动优化功能管理 Iceberg 表维护的各个方面，包括压缩和快照保留。

由于物化视图存储为 Iceberg 表，因此您可以直接从任何兼容 Iceberg 的引擎中读取它们，包括亚马逊 Athena、Amazon Redshift 和第三方分析平台。这种多引擎可访问性可确保预先计算的数据在整个分析生态系统中保持可访问性，而无需重复数据或格式转换。

## 与 AWS Lake Formation 权限集成
<a name="materialized-views-lake-formation"></a>

您可以使用 AWS Lake Formation 来管理物化视图的细粒度权限。视图创建者自动成为物化视图的所有者，并且可以使用的命名资源方法或 LF-Tag AWS Lake Formation s 向其他用户或角色授予权限。

当您授予用户对物化视图的`SELECT`权限时，他们无需访问基础源表即可查询预先计算的结果。此安全模型简化了数据访问管理，使您能够实施最小权限原则，仅向用户提供他们所需的特定数据转换的访问权限。

您可以使用跨 AWS 账户共享功能在账户、 AWS 组织和组织单位之间共享实体化视图。 AWS Lake Formation您还可以使用资源链接访问跨 AWS 区域的物化视图，从而通过分布式数据访问实现集中式数据治理。

## 监控和调试
<a name="materialized-views-monitoring-debugging"></a>

 AWS Glue 数据目录将所有实体化视图刷新操作和相关指标发布到 Amazon CloudWatch。您可以通过 CloudWatch 指标监控刷新开始时间、结束时间、持续时间、处理的数据量和刷新状态。刷新操作失败时，将在 CloudWatch 日志中捕获错误消息和诊断信息。

您可以设置 CloudWatch 警报，以便在刷新任务超过预期持续时间或重复失败时收到通知。 AWS Glue 数据目录还会将成功和失败的刷新运行的更改事件发布到，从而使您能够将实体化视图操作集成到更广泛的工作流程自动化中。

要检查实例化视图的当前状态，请使用 `DESCRIBE MATERIALIZED VIEW` SQL 命令，该命令会返回包括失效状态、上次刷新时间戳和刷新计划配置在内的元数据。

## 管理刷新作业
<a name="materialized-views-managing-refresh-jobs"></a>

### 开始手动刷新
<a name="materialized-views-manual-refresh"></a>

在计划间隔之外触发立即刷新。

必需权限：用于进行 API 调用的 AWS 凭据必须具有物化视图的`glue:GetTable`权限。

对于 S3 表目录：

```
aws glue start-materialized-view-refresh-task-run \
    --catalog-id <ACCOUNT_ID>:s3tablescatalog/<CATALOG_NAME> \
    --database-name <DATABASE_NAME> \
    --table-name <MV_TABLE_NAME>
```

对于根目录：

```
aws glue start-materialized-view-refresh-task-run \
    --catalog-id <ACCOUNT_ID> \
    --database-name <DATABASE_NAME> \
    --table-name <MV_TABLE_NAME>
```

### 正在检查刷新状态
<a name="materialized-views-checking-refresh-status"></a>

获取特定刷新任务的状态：

```
aws glue get-materialized-view-refresh-task-run \
    --catalog-id <CATALOG_ID> \
    --materialized-view-refresh-task-run-id <TASK_RUN_ID>
```

### 房源刷新历史记录
<a name="materialized-views-listing-refresh-history"></a>

查看实体化视图的所有刷新作业：

```
aws glue list-materialized-view-refresh-task-runs \
    --catalog-id <CATALOG_ID> \
    --database-name <DATABASE_NAME> \
    --table-name <MV_TABLE_NAME>
```

**注意**  
用`<ACCOUNT_ID>:s3tablescatalog/<CATALOG_NAME>`于 S3 表或`<ACCOUNT_ID>`根目录。

### 停止正在运行的刷新
<a name="materialized-views-stopping-refresh"></a>

取消正在进行的刷新作业：

```
aws glue stop-materialized-view-refresh-task-run \
    --catalog-id <CATALOG_ID> \
    --database-name <DATABASE_NAME> \
    --table-name <MV_TABLE_NAME>
```

## 监控和排查
<a name="materialized-views-monitoring-troubleshooting"></a>

有三种方法可以监视实体化视图刷新作业：

### CloudWatch 指标
<a name="materialized-views-cloudwatch-metrics"></a>

在以下位置查看所有实体化视图刷新作业的汇总指标： CloudWatch

可用指标：
+ AWS/Glue 带有维度的命名空间：
  + CatalogId: 您的目录标识符
  + DatabaseName: 包含物化视图的数据库
  + TableName: 物化视图名称
  + TaskType: 设置为 “MaterializedViewRefresh”

在控制台中查看：

1. 导航到 CloudWatch 控制台 → 指标

1. 选择 AWS/Glue 命名空间

1. 按维度筛选： CatalogId、 DatabaseName、 TableName、 TaskType

1. 查看任务成功、失败和持续时间的指标

 CloudWatch 指标查询示例：

```
{AWS/Glue,CatalogId,DatabaseName,TableName,TaskType} MaterializedViewRefresh
```

使用 AWS CLI：

```
aws cloudwatch get-metric-statistics \
    --namespace AWS/Glue \
    --metric-name <MetricName> \
    --dimensions Name=CatalogId,Value=<CATALOG_ID> \
                 Name=DatabaseName,Value=<DATABASE_NAME> \
                 Name=TableName,Value=<TABLE_NAME> \
                 Name=TaskType,Value=MaterializedViewRefresh \
    --start-time <START_TIME> \
    --end-time <END_TIME> \
    --period 3600 \
    --statistics Sum \
    --region <REGION>
```

### CloudWatch 日志
<a name="materialized-views-cloudwatch-logs"></a>

查看各个刷新任务运行的详细执行日志：

日志组：`/aws-glue/materialized-views/<task_run_id>`

UUID 在`<task_run_id>`哪里（例如 abc12345-def6-7890-ghij-klmnopqrstuv）。

查看日志：

```
# List log streams for a task run
aws logs describe-log-streams \
    --log-group-name /aws-glue/materialized-views/<TASK_RUN_ID> \
    --region <REGION>

# Get log events
aws logs get-log-events \
    --log-group-name /aws-glue/materialized-views/<TASK_RUN_ID> \
    --log-stream-name <LOG_STREAM_NAME> \
    --region <REGION>
```

在 CloudWatch 控制台中：

1. 导航至 CloudWatch → 日志组

1. 搜索 /aws-glue/materialized-views/

1. 选择带有您的任务运行 ID 的日志组

1. 查看详细的执行日志、错误和 Spark 任务输出

### 通知
<a name="materialized-views-eventbridge"></a>

订阅事件以获取有关刷新作业状态更改的实时通知：

可用的事件类型：
+ Glue 物化视图刷新任务已启动
+ Glue 物化视图刷新任务成功
+ Glue 物化视图刷新任务失败
+ Glue 物化视图自动刷新调用失败

创建规则：

```
aws events put-rule \
    --name materialized-view-refresh-notifications \
    --event-pattern '{
        "source": ["aws.glue"],
        "detail-type": [
            "Glue Materialized View Refresh Task Started",
            "Glue Materialized View Refresh Task Succeeded",
            "Glue Materialized View Refresh Task Failed",
            "Glue Materialized View Auto-Refresh Invocation Failure"
        ]
    }' \
    --region <REGION>
```

添加目标（例如，SNS 主题）：

```
aws events put-targets \
    --rule materialized-view-refresh-notifications \
    --targets "Id"="1","Arn"="arn:aws:sns:<REGION>:<ACCOUNT_ID>:<TOPIC_NAME>" \
    --region <REGION>
```

### 查看刷新状态
<a name="materialized-views-refresh-status"></a>

使用 AWS Glue API 检查您的物化视图刷新任务的状态：

```
aws glue get-materialized-view-refresh-task-run \
    --catalog-id <CATALOG_ID> \
    --materialized-view-refresh-task-run-id <TASK_RUN_ID> \
    --region <REGION>
```

或者列出所有最近的刷新运行：

```
aws glue list-materialized-view-refresh-task-runs \
    --catalog-id <CATALOG_ID> \
    --database-name <DATABASE_NAME> \
    --table-name <MV_TABLE_NAME> \
    --region <REGION>
```

这显示：
+ 上次刷新时间
+ 刷新状态（成功、失败、正在运行、已停止）
+ 任务运行 ID
+ 错误消息（如果失败）

常见刷新状态：
+ 正在运行：刷新作业当前正在执行
+ 成功：刷新成功完成
+ 失败：刷新遇到错误
+ 已停止：刷新已手动取消

刷新失败疑难解答：

如果刷新失败，请检查：

1. IAM 权限：确保定义者角色有权访问所有基表和物化视图位置

1. 基表可用性：验证所有引用的表都存在并且可以访问

1. 查询有效性：确认 SQL 查询对 Spark SQL 方言有效

1. 资源限制：检查您的账户是否已达到并发刷新上限

使用 GetMaterializedViewRefreshTaskRun API 检索详细的错误消息。

## 注意事项和限制
<a name="materialized-views-considerations-limitations"></a>
+ 物化视图只能引用在 AWS Glue 数据目录中注册的 Apache Iceberg 表作为基表。
+ 视图创建和自动查询重写仅适用于亚马逊 Athena、亚马逊 EMR 和（版本 5.1）的 Apache Spark 3.5.6 及更高版本的 Spark 引擎。 AWS Glue 
+ 物化视图最终与基表保持一致。在刷新窗口期间，直接访问物化视图的查询可能会返回过期的数据。要立即访问当前数据，请执行手动刷新。
+ 最小自动刷新间隔为一小时。对于需要更频繁更新的用例，请使用命令以编程方式执行手动刷新。`REFRESH MATERIALIZED VIEW`
+ 查询重写优先考虑正确性而不是性能。如果物化视图过时或无法准确满足查询要求，则 Spark 引擎会对基表执行原始查询。