

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS Glue Data Catalog 뷰 빌드
<a name="working-with-views"></a>

에서 AWS Glue Data Catalog*뷰*는 하나 이상의 테이블을 참조하는 SQL 쿼리에 의해 콘텐츠가 정의되는 가상 테이블입니다. EMR Serverless 또는 AWS Glue 버전 5.0을 사용하여 Amazon Athena, Amazon Redshift 또는 Apache Spark용 SQL 편집기를 사용하여 최대 10개의 테이블을 참조하는 데이터 카탈로그 뷰를 생성할 수 있습니다. 뷰의 기본 참조 테이블은 동일한 데이터베이스 또는 동일한 데이터 카탈로그 내의 다른 데이터베이스에 속할 수 AWS 계정있습니다.

[Apache Hudi, Linux Foundation Delta Lake, Apache](https://hudi.incubator.apache.org/) [Iceberg](https://iceberg.apache.org/)와 같은 개방형 테이블 형식(OTF)의 표준 AWS Glue 테이블과 테이블을에 등록된 Amazon S3 위치에 저장된 기본 데이터와 함께 참조할 수 있습니다 AWS Lake Formation. [https://delta.io/](https://delta.io/) 또한 Lake Formation과 공유되는 Amazon Redshift 데이터 공유의 연동 테이블에서 뷰를 생성할 수 있습니다.

## 다른 뷰 유형과 데이터 카탈로그 뷰 구분
<a name="diff-views"></a>

데이터 카탈로그 뷰는 Apache Hive, Apache Spark 및 Amazon Athena 뷰와 다릅니다. Data Catalog 뷰는의 기본 기능 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 태그를 사용하여 데이터 카탈로그 뷰에 대한 세분화된 권한을 부여하고 AWS 계정, AWS 조직 및 조직 단위 간에 공유할 수 있습니다. 리소스 링크를 AWS 리전 사용하여 간에 데이터 카탈로그 뷰를 공유하고 액세스할 수도 있습니다. 이를 통해 사용자는 데이터 소스를 복제하고 기존 테이블을 공유하지 않고도 데이터 액세스를 제공할 수 있습니다.

데이터 카탈로그 보기의 `CREATE VIEW` DDL 문은 Hudi, Delta Lake 및 Iceberg와 같은 개방형 테이블 형식(OTF)의 표준 AWS Glue 테이블과 테이블을 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
+ EMR Serverless의 Apache Spark
+  AWS Glue 버전 5.0의 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>
+ 데이터 카탈로그에서 뷰를 생성하려면 참조 테이블의 기본 Amazon S3 데이터 위치를 Lake Formation에 등록해야 합니다. Lake Formation에 데이터를 등록하는 방법에 대한 자세한 내용은 [데이터 레이크에 Amazon S3 위치 추가](register-data-lake.md) 섹션을 참조하십시오.
+ IAM 역할만 데이터 카탈로그 뷰를 생성할 수 있습니다. 다른 IAM ID로는 데이터 카탈로그 뷰를 생성할 수 없습니다.
+ 뷰를 정의하는 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에 대한 iam: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 및 API/를 사용하여 AWS Glue Data Catalog 뷰를 생성할 수 있습니다AWS CLI. AWS Glue APIs

SQL 편집기를 사용하여 데이터 카탈로그 뷰를 생성하려면 Athena 또는 Redshift Spectrum을 선택하고 `CREATE VIEW` 데이터 정의 언어(DDL) 문을 사용하여 뷰를 생성합니다. 첫 번째 엔진의 언어에서 뷰를 생성한 후 두 번째 엔진의 `ALTER VIEW` DDL 문을 사용하여 추가 언어를 추가할 수 있습니다.

뷰를 정의할 때 다음을 고려하는 것이 중요합니다.
+ **다중 언어 뷰 정의** - 여러 언어로 뷰를 정의할 때 서로 다른 언어의 스키마가 일치해야 합니다. 각 SQL 언어의 구문 사양은 약간 다릅니다. 데이터 카탈로그 뷰를 정의하는 쿼리 구문은 모든 언어에서 유형과 이름을 모두 포함하여 정확히 동일한 열 목록으로 해석되어야 합니다. 이 정보는 뷰의 `StorageDescriptor`에 저장됩니다. 또한 언어는 데이터 카탈로그에서 동일한 기본 테이블 객체를 참조해야 합니다.

  `ALTER VIEW` 문을 사용하여 DDL로 뷰에 다른 언어를 추가할 수 있습니다. `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` 유형 필드가 있고 다른 엔진이 해당 열을 구문(`<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 데이터 카탈로그 뷰 쿼리 구문](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)

  데이터 카탈로그의 뷰와 관련된 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/ko_kr/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` 필드가 있습니다.

지원되는 각 쿼리 엔진 Amazon Athena 과 Amazon Redshift에 대해 SQL 언어를 검증하는 데 두 가지 새로운 AWS Glue 연결을 사용할 수 있습니다.

뷰와 사용하면 `CreateTable` 및 `UpdateTable` API는 비동기식입니다. 해당 API는 여러 SQL 언어로 직접 호출하면 각 엔진에서 직접 호출을 검증하여 해당 엔진에서 언어를 실행할 수 있는지 및 각 언어에서 뷰의 결과적인 스키마가 일치하는지 여부를 확인합니다. 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>

`CreateTable` 또는 `UpdateTable` 작업을 사용하여 AWS Glue Data Catalog 뷰를 생성하거나 업데이트하려면 검증을 위해 새 유형의 AWS Glue 연결을 생성하고 지원되는 분석 엔진에 제공해야 합니다. 해당 연결은 Athena 또는 Amazon Redshift에서 데이터 카탈로그 뷰를 사용하기 위해 필요합니다. 이러한 연결은 AWS CLI, AWS SDKs 또는 AWS Glue APIs. AWS Management Console 를 사용하여 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 서비스는 엔진이 반환하는 오류 메시지를 제공합니다.

**상태 필드**  
다음은 상태 필드입니다.
+ 상태: 다양한 유형의 작업과 무관한 일반 상태:
  + 대기됨
  + IN\$1PROGRESS
  + 성공
  + FAILED
+ 작업 - 테이블에서 직접적으로 호출된 작업을 나타냅니다. 현재 `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. 대기됨

   1. IN\$1PROGRESS

   1. 성공

   1. FAILED

또한 데이터 카탈로그 뷰의 일부 업데이트에는 비동기 작업이 필요하지 않습니다. 테이블의 `Description` 특성을 업데이트하려는 경우를 예로 들어보겠습니다. 비동기 작업이 필요하지 않으므로 결과 테이블 메타데이터에는 `Status`가 없으며 특성은 `NULL`입니다.

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

다음으로이 주제에서는 위의 상태 정보가 AWS Glue 뷰에서 수행할 수 있는 작업에 어떤 영향을 미칠 수 있는지 살펴봅니다.

**glue:CreateTable**  
Glue 테이블에 대해 `glue:CreateTable`이 작동하는 방식을 비교할 때 이 API에는 변경 사항이 없습니다. `CreateTable`은 아직 존재하지 않는 테이블 이름에 대해 직접적으로 호출될 수 있습니다.

**glue:UpdateTable**  
다음 상태 정보가 있는 AWS Glue 뷰에서는이 작업을 수행할 수 없습니다.

1. 작업 == CREATE 및 State == QUEUED

1. 작업 == CREATE 및 State == IN\$1PROGRESS

1. 작업 == CREATE 및 state == FAILED

1. 작업 == UPDATE 및 state == QUEUED

1. 작업 == UPDATE 및 state == IN\$1PROGRESS

요약하자면 다음 요구 사항을 충족하는 경우에만 데이터 카탈로그 뷰를 업데이트할 수 있습니다.

1. 처음 성공적으로 생성되었습니다.

   1. 작업 == CREATE 및 State == SUCCESS

1. 비동기 업데이트 작업 후 터미널 상태에 도달했습니다.

   1. 작업 == UPDATE 및 State == SUCCESS

   1. 작업 == UPDATE 및 State == FAILED

1. 동기 업데이트의 결과로 상태 특성은 `NULL`입니다.

**glue:DeleteTable**  
가 AWS Glue 테이블에 대해 `glue:DeleteTable` 작동하는 방식과 비교할 때이 작업에는 변경 사항이 없습니다. 상태와 무관하게 데이터 카탈로그 뷰를 삭제할 수 있습니다.

**glue:GetTable**  
가 AWS Glue 테이블에 대해 `glue:GetTable` 작동하는 방식과 비교할 때이 작업에는 변경 사항이 없습니다. 그러나 처음으로 성공적으로 생성될 때까지 분석 엔진에서 데이터 카탈로그 뷰를 쿼리할 수 없습니다. `Action == CREATE and State == SUCCESS`. 데이터 카탈로그 뷰를 처음 성공적으로 생성한 후에는 상태와 무관하게 뷰를 쿼리할 수 있습니다.

**참고**  
이 섹션의 모든 정보는 `GetTable`, `GetTables`, `SearchTables` 등 모든 테이블 읽기 API에 적용됩니다.

# 비동기 작업 중 뷰 생성 실패 시나리오
<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 연결은 제공된 클러스터 및 서버리스 엔드포인트에 존재하지 않는 Amazon Redshift 데이터베이스를 참조하므로 잘못된 형식입니다. Amazon Redshift는 뷰를 검증할 수 없으며 `GetTable` 응답의 `Status` 필드에 오류(Amazon Redshift의 `"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>

쿼리에서 데이터베이스 이름의 맞춤법이 잘못되었으므로 SQL for Athena는 유효하지 않습니다. 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`를 선택하고 SQL for Redshift는 `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 데이터 카탈로그에서 구체화된 뷰는 SQL 쿼리의 미리 계산된 결과를 Apache Iceberg 형식으로 저장하는 관리형 테이블입니다. 쿼리에 액세스할 때마다 쿼리를 실행하는 표준 Data Catalog 뷰와 달리 구체화된 뷰는 쿼리 결과를 물리적으로 저장하고 기본 소스 테이블이 변경될 때 업데이트합니다. Amazon Athena, Amazon EMR 또는에서 Apache Spark 버전 3.5.6 이상을 사용하여 구체화된 뷰를 생성할 수 있습니다 AWS Glue.

구체화된 뷰는 AWS Glue 데이터 카탈로그에 등록된 Apache Iceberg 테이블을 참조하며, 사전 계산된 데이터는 Amazon S3 Tables 버킷 또는 Amazon S3 범용 버킷의 Apache Iceberg 테이블로 저장되므로 Amazon Athena, Amazon Redshift 및 타사 Iceberg 호환 엔진을 비롯한 여러 쿼리 엔진에서 액세스할 수 있습니다.

## 구체화된 뷰를 다른 뷰 유형과 구분
<a name="materialized-views-differentiating"></a>

구체화된 뷰는 기본적인 방식으로 AWS Glue 데이터 카탈로그 뷰, Apache Spark 뷰 및 Amazon Athena 뷰와 다릅니다. Data Catalog 뷰는 액세스할 때마다 SQL 쿼리 정의를 실행하는 가상 테이블이지만 구체화된 뷰는 미리 계산된 쿼리 결과를 물리적으로 저장합니다. 따라서 중복 계산이 필요 없으며 자주 액세스하는 복잡한 변환에 대한 쿼리 성능이 크게 향상됩니다.

구체화된 뷰는 AWS Glue ETL 또는 사용자 지정 Spark 작업으로 구축된 기존 데이터 변환 파이프라인과도 다릅니다. 변경 감지, 증분 업데이트 및 워크플로 오케스트레이션을 처리하는 사용자 지정 코드를 작성하는 대신 표준 SQL 구문을 사용하여 구체화된 뷰를 정의합니다. 데이터 카탈로그는 AWS Glue 소스 테이블을 자동으로 모니터링하고, 변경 사항을 감지하고, 완전 관리형 컴퓨팅 인프라를 사용하여 구체화된 뷰를 새로 고칩니다.

## 사용 사례
<a name="materialized-views-use-cases"></a>

구체화된 뷰의 중요한 사용 사례는 다음과 같습니다.
+ **복잡한 분석 쿼리 가속화** - 비용이 많이 드는 조인, 집계 및 창 함수를 미리 계산하는 구체화된 뷰를 생성합니다. Spark 엔진은 사전 계산된 결과를 사용하기 위해 후속 쿼리를 자동으로 다시 작성하여 쿼리 지연 시간과 컴퓨팅 비용을 줄입니다.
+ **데이터 변환 파이프라인 간소화** - 변경 감지, 증분 업데이트 및 워크플로 오케스트레이션을 처리하는 복잡한 ETL 작업을 간단한 SQL 기반 구체화된 뷰 정의로 대체합니다. AWS Glue 데이터 카탈로그는 모든 운영 복잡성을 자동으로 관리합니다.
+ **관리형 데이터 액세스를 통한 셀프 서비스 분석 활성화 -** 원시 데이터를 비즈니스용 데이터 세트로 변환하는 큐레이트된 구체화된 뷰를 생성합니다. 기본 소스 테이블을 노출하지 않고 구체화된 뷰에 대한 액세스 권한을 사용자에게 부여하여 보안 관리를 간소화하는 동시에 셀프 서비스 분석을 강화합니다.
+ **기계 학습을 위한 특성 엔지니어링 최적화** - ML 모델에 대한 특성 변환을 구현하는 구체화된 뷰를 정의합니다. 자동 새로 고침 기능은 소스 데이터가 발전함에 따라 특성 저장소를 최신 상태로 유지하는 동시에 증분 새로 고침은 컴퓨팅 비용을 최소화합니다.
+ **효율적인 데이터 공유 구현** - 특정 소비자의 데이터를 필터링하고 변환하는 구체화된 뷰를 생성합니다. 를 사용하여 계정 및 리전 간에 구체화된 보기를 공유 AWS Lake Formation하므로 중앙 집중식 거버넌스를 유지하면서 데이터 중복이 필요하지 않습니다.

## 주요 개념
<a name="materialized-views-key-concepts"></a>

### 자동 새로 고침
<a name="materialized-views-automatic-refresh"></a>

자동 새로 고침은 소스 테이블을 지속적으로 모니터링하고 정의한 일정에 따라 구체화된 뷰를 업데이트하는 기능입니다. 구체화된 뷰를 생성할 때 간격이 1시간인 시간 기반 일정을 사용하여 새로 고침 빈도를 지정할 수 있습니다. 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 Tables 버킷에 저장된 경우 역할에 다음 권한도 추가해야 합니다.

```
{
  "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>

구체화된 뷰는 사전 계산된 결과를 AWS 계정 내의 S3 Tables 버킷 또는 범용 S3 버킷에 Apache Iceberg 테이블로 저장합니다. AWS Glue 데이터 카탈로그는 S3 Tables의 자동 최적화 기능을 통해 압축 및 스냅샷 보존을 포함하여 Iceberg 테이블 유지 관리의 모든 측면을 관리합니다.

구체화된 뷰는 Iceberg 테이블로 저장되므로 Amazon Athena, Amazon Redshift 및 타사 분석 플랫폼을 포함한 모든 Iceberg 호환 엔진에서 직접 읽을 수 있습니다. 이러한 다중 엔진 접근성을 통해 데이터 복제 또는 형식 변환 없이 전체 분석 에코시스템에서 사전 계산된 데이터에 계속 액세스할 수 있습니다.

## AWS Lake Formation 권한과 통합
<a name="materialized-views-lake-formation"></a>

 AWS Lake Formation 를 사용하여 구체화된 뷰에 대한 세분화된 권한을 관리할 수 있습니다. 뷰 생성자는 구체화된 뷰의 소유자가 되며 AWS Lake Formation명명된 리소스 메서드 또는 LF 태그를 사용하여 다른 사용자 또는 역할에 권한을 부여할 수 있습니다.

구체화된 뷰에 대한 `SELECT` 권한을 사용자에게 부여하면 기본 소스 테이블에 액세스할 필요 없이 미리 계산된 결과를 쿼리할 수 있습니다. 이 보안 모델은 데이터 액세스 관리를 간소화하고 최소 권한 원칙을 구현하여 사용자에게 필요한 특정 데이터 변환에만 액세스할 수 있는 권한을 제공합니다.

 AWS Lake Formation의 교차 AWS 계정 공유 기능을 사용하여 계정, AWS 조직 및 조직 단위 간에 구체화된 보기를 공유할 수 있습니다. 리소스 링크를 사용하여 AWS 여러 리전에서 구체화된 뷰에 액세스하여 분산 데이터 액세스를 통해 중앙 집중식 데이터 거버넌스를 활성화할 수도 있습니다.

## 모니터링 및 디버깅
<a name="materialized-views-monitoring-debugging"></a>

 AWS Glue 데이터 카탈로그는 구체화된 모든 보기 새로 고침 작업 및 관련 지표를 Amazon CloudWatch에 게시합니다. CloudWatch 지표를 통해 새로 고침 시작 시간, 종료 시간, 기간, 처리된 데이터 볼륨 및 새로 고침 상태를 모니터링할 수 있습니다. 새로 고침 작업이 실패하면 오류 메시지와 진단 정보가 CloudWatch Logs에 캡처됩니다.

새로 고침 작업이 예상 기간을 초과하거나 반복적으로 실패할 때 알림을 받도록 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>
```

**참고**  
S3 테이블`<ACCOUNT_ID>:s3tablescatalog/<CATALOG_NAME>`의 경우를 사용하고 루트 카탈로그의 `<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. Select 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 Logs
<a name="materialized-views-cloudwatch-logs"></a>

개별 새로 고침 작업 실행에 대한 세부 실행 로그를 봅니다.

로그 그룹: `/aws-glue/materialized-views/<task_run_id>`

여기서 `<task_run_id>`는 UUID(예: 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>
```

이는 다음을 보여줍니다.
+ 마지막 새로 고침 시간
+ 새로 고침 상태(SUCCEEDED, FAILED, RUNNING, STOPPED)
+ 작업 실행 ID
+ 오류 메시지(실패한 경우)

일반적인 새로 고침 상태:
+ 실행 중: 새로 고침 작업이 현재 실행 중입니다.
+ 성공: 새로 고침이 성공적으로 완료되었습니다.
+ FAILED: 새로 고침에 오류가 발생했습니다.
+ 중지됨: 새로 고침이 수동으로 취소됨

실패한 새로 고침 문제 해결:

새로 고침에 실패하면 다음을 확인합니다.

1. IAM 권한: 정의자 역할이 모든 기본 테이블 및 구체화된 뷰 위치에 액세스할 수 있는지 확인합니다.

1. 기본 테이블 가용성: 참조된 모든 테이블이 존재하고 액세스할 수 있는지 확인

1. 쿼리 유효성: SQL 쿼리가 Spark SQL 언어에 유효한지 확인

1. 리소스 제한: 계정의 동시 새로 고침 제한에 도달했는지 확인합니다.

GetMaterializedViewRefreshTaskRun API를 사용하여 자세한 오류 메시지를 검색합니다.

## 고려 사항 및 제한 사항
<a name="materialized-views-considerations-limitations"></a>
+ 구체화된 뷰는 AWS Glue 데이터 카탈로그에 기본 테이블로 등록된 Apache Iceberg 테이블만 참조할 수 있습니다.
+ 보기 생성 및 자동 쿼리 재작성은 Amazon Athena, Amazon EMR 및 AWS Glue (버전 5.1)에서 Apache Spark 버전 3.5.6 이상의 Spark 엔진에서만 사용할 수 있습니다.
+ 구체화된 뷰는 결국 기본 테이블과 일치합니다. 새로 고침 기간 동안 구체화된 뷰에 직접 액세스하는 쿼리는 오래된 데이터를 반환할 수 있습니다. 현재 데이터에 즉시 액세스하려면 수동 새로 고침을 실행합니다.
+ 최소 자동 새로 고침 간격은 1시간입니다. 더 자주 업데이트해야 하는 사용 사례의 경우 `REFRESH MATERIALIZED VIEW` 명령을 사용하여 프로그래밍 방식으로 수동 새로 고침을 실행합니다.
+ 쿼리 재작성은 성능보다 정확성을 우선시합니다. 구체화된 뷰가 오래되었거나 쿼리 요구 사항을 정확하게 충족할 수 없는 경우 Spark 엔진은 기본 테이블에 대해 원래 쿼리를 실행합니다.