Iceberg Catalog
Doris는 다양한 메타데이터 서비스를 통해 Iceberg 테이블 데이터에 접근할 수 있습니다. 데이터 읽기뿐 아니라 INSERT, INSERT OVERWRITE, UPDATE, DELETE, MERGE INTO를 포함한 Iceberg 테이블 쓰기도 지원합니다.
Apache Doris와 Apache Iceberg 빠르게 시작하기.
Hive Catalog를 통해 Hive Metastore를 메타데이터 서비스로 사용하는 Iceberg 테이블에 접근할 수 있습니다. 다만 일부 호환성 문제를 방지하려면 Iceberg Catalog를 직접 사용하는 것이 좋습니다.
활용 시나리오
| 시나리오 | 설명 |
|---|---|
| 쿼리 가속 | Doris의 분산 컴퓨팅 엔진으로 Iceberg 데이터에 직접 접근하여 쿼리 속도를 높입니다. |
| 데이터 통합 | Iceberg 데이터를 읽어 Doris 내부 테이블에 쓰거나, Doris 컴퓨팅 엔진으로 ZeroETL 작업을 수행합니다. |
| 데이터 다시 쓰기 | Doris가 지원하는 모든 데이터 소스의 데이터를 처리하고 Iceberg 테이블 스토리지에 다시 씁니다. |
Catalog 구성
구문
CREATE CATALOG [IF NOT EXISTS] catalog_name PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = '<iceberg_catalog_type>',
'warehouse' = '<warehouse>', --optional
{MetaStoreProperties},
{StorageProperties},
{IcebergProperties},
{CommonProperties}
);
-
<iceberg_catalog_type>Iceberg Catalog의 유형으로, 다음 옵션을 지원합니다.
-
hms: Hive Metastore를 메타데이터 서비스로 사용합니다. -
rest: Iceberg Rest Catalog 인터페이스와 호환되는 메타데이터 서비스입니다. -
hadoop: 파일 시스템에 저장된 메타데이터에 직접 접근합니다. -
glue: AWS Glue를 메타데이터 서비스로 사용합니다. -
dlf: Alibaba Cloud DLF를 메타데이터 서비스로 사용합니다. -
jdbc: Iceberg JDBC Catalog를 메타데이터 서비스로 사용합니다. -
s3tables: AWS S3 Tables Catalog를 사용하여 S3 Table Bucket에 접근합니다.
-
-
<warehouse>Iceberg의 웨어하우스 경로입니다. 이 매개변수는
<iceberg_catalog_type>이hadoop일 때 반드시 지정해야 합니다.warehouse경로는Database경로의 상위 수준을 가리켜야 합니다. 예를 들어 테이블 경로가s3://bucket/path/to/db1/table1이면warehouse는s3://bucket/path/to/여야 합니다. -
{MetaStoreProperties}MetaStoreProperties에는 Metastore 메타데이터 서비스의 연결 및 인증 정보를 입력합니다. [지원되는 메타데이터 서비스] 섹션을 참조하세요.
-
{StorageProperties}StorageProperties에는 스토리지 시스템의 연결 및 인증 정보를 입력합니다. [지원되는 스토리지 시스템] 섹션을 참조하세요.
-
{IcebergProperties}IcebergProperties에는 Iceberg Catalog 전용 매개변수를 입력합니다.
-
list-all-tablesHive Metastore를 메타데이터 서비스로 사용하는 Iceberg Catalog에 적용됩니다. 기본값은
true입니다. 기본적으로SHOW TABLES작업은 현재 데이터베이스에 있는 모든 유형의 테이블을 나열합니다(Hive Metastore에는 Iceberg 이외 유형의 테이블도 저장될 수 있습니다). 이 방식의 성능이 가장 좋습니다.false로 설정하면 Doris가 각 테이블의 유형을 하나씩 확인하여 Iceberg 유형의 테이블만 반환합니다. 이 모드는 테이블이 많을 때 성능이 떨어집니다. -
iceberg.rest.view-enabled버전 4.0.6부터 지원됩니다.
Iceberg REST Catalog에만 적용됩니다. 뷰 관련 작업(
listViews,loadView,viewExists,dropView등)의 활성화 여부를 지정합니다. 기본값은true입니다.일부 Iceberg REST Catalog 구현은 테이블 API를 제공하지만 뷰 API는 사용할 수 없거나 오류를 반환합니다.
SHOW TABLES를 실행할 때 Doris는ViewCatalog.listViews()를 호출하여 테이블 목록에서 뷰를 제외하므로, 이러한 REST 서비스에서는SHOW TABLES와 테이블 메타데이터 로딩이 실패할 수 있습니다.이 경우 이 매개변수를
false로 설정하면 Doris가 모든 뷰 관련 작업을 건너뛰어SHOW TABLES와 같은 메타데이터 작업을 정상적으로 수행할 수 있습니다.
-
-
{CommonProperties}CommonProperties에는 일반 속성을 입력합니다. 공통 속성에 대한 자세한 내용은 Catalog 개요를 참조하세요.
메타데이터 캐시
Apache Doris는 외부 데이터 소스에 접근하는 성능을 높이기 위해 Iceberg 메타데이터를 캐시합니다. 메타데이터에는 테이블 구조(Schema), 테이블 객체, 스냅샷, 뷰 객체, manifest 세부 정보가 포함됩니다.
Doris 4.1.x 이전 버전에서는 주로 FE 구성 항목으로 메타데이터 캐시를 전역 제어합니다. 자세한 내용은 메타데이터 캐시를 참조하세요.
Doris 4.1.x부터는 통합된 meta.cache.* 키로 Iceberg Catalog의 외부 메타데이터 캐시를 구성합니다.
캐시 속성 구성(4.1.x+)
각 엔진의 캐시 항목은 통합된 구성 키 형식인 meta.cache.<engine>.<entry>.{enable,ttl-second,capacity,max-weight}를 사용합니다. 메모리 제한은 메모리 사용량 추정 기능이 있는 항목에만 적용됩니다. 외부 메타데이터 캐시 메모리 관리를 참조하세요.
| 속성 | 예시 | 의미 |
|---|---|---|
enable | true/false | 이 캐시 모듈을 활성화할지 여부입니다. |
ttl-second | 600, 0, -1 | 0은 캐시 비활성화를 의미하며 즉시 적용됩니다(최신 데이터를 확인하는 데 사용할 수 있음). -1은 만료되지 않음을 의미합니다. 그 외 양의 정수는 접근 시간을 기준으로 한 TTL(초)을 의미합니다. |
capacity | 10000 | 캐시 항목의 최대 개수입니다. max-weight가 활성화된 경우 개수 제한을 동시에 적용하지 않지만, 0으로 설정하면 여전히 캐시가 비활성화됩니다. |
max-weight | 1GB | Doris 4.1.4부터 지원됩니다. 선택적으로 설정하는 예상 유지 메모리 한도입니다. Iceberg의 table, snapshot, manifest가 지원하며, 0으로 설정하면 해당 항목이 비활성화됩니다. |
적용 조건: 모듈 캐시는 enable=true, ttl-second != 0, capacity > 0이고, max-weight가 설정되지 않았거나 0이 아닐 때 적용됩니다.
캐시 모듈
Iceberg Catalog에는 다음 캐시 모듈이 포함됩니다.
모듈(<entry>) | 속성 키 접두사 | 캐시 내용 및 영향 |
|---|---|---|
schema | meta.cache.iceberg.schema. | 테이블 구조를 캐시합니다. 영향: 테이블 컬럼 정보의 가시성에 영향을 줍니다. 비활성화하면 쿼리마다 최신 Schema를 가져옵니다. |
table | meta.cache.iceberg.table. | Iceberg 테이블 메타데이터 객체를 캐시합니다. 영향: Catalog/Metastore 왕복 요청을 줄입니다. |
snapshot | meta.cache.iceberg.snapshot. | 스냅샷 메타데이터와 유지 중인 테이블 세대를 캐시합니다. 영향: 스냅샷과 파티션 프로젝션의 반복 로딩을 줄입니다. 이 항목은 max-weight를 지원합니다. |
view | meta.cache.iceberg.view. | Iceberg 뷰 메타데이터 객체를 캐시합니다. |
manifest | meta.cache.iceberg.manifest. | manifest 세부 정보를 캐시합니다. 영향: manifest에 반복 접근하는 오버헤드를 줄입니다. 참고: 이 모듈은 기본적으로 비활성화되어 있으므로 수동으로 활성화해야 합니다. |
기존 매개변수 매핑 및 변환
버전 4.1.x 이상에서는 통합 키를 사용하는 것이 좋습니다. 다음은 기존 Catalog 속성과 4.1.x+ 통합 키 사이의 매핑입니다.
| 기존 속성 키 | 4.1.x+ 통합 키 | 설명 |
|---|---|---|
schema.cache.ttl-second | meta.cache.iceberg.schema.ttl-second | 테이블 구조 캐시의 만료 시간 |
모범 사례
- 최신 데이터에 실시간 접근: 쿼리마다 Iceberg 테이블의 최신 스냅샷이나 스키마 변경 사항을 확인하려면
ttl-second를schema또는table에 대해0으로 설정할 수 있습니다.-- Disable table object cache to detect snapshot changes
ALTER CATALOG iceberg_ctl SET PROPERTIES ("meta.cache.iceberg.table.ttl-second" = "0"); - 성능 최적화:
- manifest 캐시를 활성화하면 대형 테이블의 쿼리 계획 수립 속도를 크게 높일 수 있습니다.
ALTER CATALOG iceberg_ctl SET PROPERTIES (
"meta.cache.iceberg.manifest.enable" = "true",
"meta.cache.iceberg.manifest.ttl-second" = "600"
); - Doris 4.1.4부터는 Catalog 속성 변경이 성공하면 Catalog 실행 컨텍스트가 초기화되고, 해당 Catalog가 라우팅하는 모든 메타데이터 캐시 엔진에서 초기화된 항목이 삭제됩니다. Doris는 다음 접근 시 새 컨텍스트와 구성으로 항목을 다시 생성합니다. 실행 중인 쿼리는 영향을 받지 않습니다.
- manifest 캐시를 활성화하면 대형 테이블의 쿼리 계획 수립 속도를 크게 높일 수 있습니다.
관측 가능성
캐시 메트릭은 information_schema.catalog_meta_cache_statistics 시스템 테이블에서 확인할 수 있습니다.
SELECT catalog_name, engine_name, entry_name,
effective_enabled, ttl_second, capacity,
estimated_size, hit_rate, load_failure_count, last_error
FROM information_schema.catalog_meta_cache_statistics
WHERE catalog_name = 'iceberg_ctl' AND engine_name = 'iceberg'
ORDER BY entry_name;
이 시스템 테이블의 문서인 catalog_meta_cache_statistics를 참조하세요.
지원되는 Iceberg 버전
| Doris 버전 | Iceberg SDK 버전 |
|---|---|
| 2.1 | 1.6.1 |
| 3.0 | 1.6.1 |
| 3.1 | 1.9.1 |
| 4.0 | 1.9.1 |
| 4.1.4 / 4.1.4.1 | 1.10.1 |
| 4.1.5+ | 1.11.0 |
메타데이터 및 읽기 오류(4.1.5부터)
DESCRIBE,SHOW COLUMNS,SHOW CREATE TABLE은 현재 Iceberg 스키마의 필수/선택 선언을 보존합니다. 스캔은 스키마 진화로 인해 누락된 필드도 계속 처리합니다. NOT NULL 선언이 표시되더라도 모든 과거 파일에 해당 필드가 존재한다는 의미는 아닙니다.- 매핑할 수 없는 유형을 포함하는 과거 파티션 사양은 일반 읽기와 행 수준 DML에 서로 다른 영향을 줄 수 있습니다.
DELETE또는UPDATE는 Iceberg Row ID를 구성하지 못하고Cannot produce Iceberg row IDs with unsupported partition types in spec ...오류로 실패할 수 있습니다. 행 수준 변경을 수행하기 전에 테이블 형식에서 지원하는 쓰기 도구로 과거 데이터 파일을 다시 작성하세요. - 커밋된 스냅샷이 참조하는 데이터 파일이나 삭제 파일이 누락되면
ignore_not_found_file_in_external_table=true인 경우에도 쿼리가 실패합니다. 누락된 객체를 복원하거나 파일이 모두 존재하는 유효한 스냅샷을 선택하세요. schema.name-mapping.default는 유효한 Iceberg Name Mapping JSON 배열이어야 합니다. 값이 유효하지 않으면 현재 컬럼 이름으로 대체하여 NULL을 반환하는 대신 데이터 스캔이 실패합니다. Spark와 같은 쓰기 도구로 속성을 수정하거나 제거한 다음 Doris에서 테이블을 새로 고치세요. 메타데이터 시스템 테이블 쿼리는 이 데이터 스캔 검증을 수행하지 않습니다.
지원되는 Iceberg 형식
- Iceberg V1/V2 형식을 지원합니다.
- Position Delete와 Equality Delete 읽기를 지원합니다.
- Deletion Vector 읽기를 지원합니다(4.1.0부터).
지원되는 메타데이터 서비스
- Hive Metastore
- AWS Glue
- Aliyun DLF
- Iceberg Rest Catalog
- Iceberg JDBC Catalog(버전 4.1.0부터 지원)
- FileSystem
참고: Doris 버전마다 지원되는 서비스 유형과 매개변수가 조금씩 다릅니다. [예제] 섹션을 참조하세요.
Iceberg Catalog 기능 지원 매트릭스
| 메타데이터 서비스 | 테이블 쿼리 | 뷰 쿼리 | DDL 작업 | 데이터 다시 쓰기 | 시스템 테이블(3.1+부터 지원) |
|---|---|---|---|---|---|
| Hive MetaStore | ✅ | ✅ | ✅ | ✅ | ✅ |
| AWS Glue | ✅ | ✅ | ❌ | ❌ | ✅ |
| Aliyun DLF | ✅ | ✅ | ❌ | ❌ | ❌ |
| Iceberg Rest Catalog | ✅ | ✅ | 서비스 제공자에 따라 다름 | 서비스 제공자에 따라 다름 | 서비스 제공자에 따라 다름 |
| FileSystem | ✅ | ✅ | ✅ | ✅ | ✅ |
지원되는 스토리지 시스템
- HDFS
- AWS S3
- Google Cloud Storage
- Azure Blob
- Apache Ozone(4.0.4부터 지원)
- Aliyun OSS
- Tencent COS
- Huawei OBS
- MINIO
- SeaweedFS
참고: Doris 버전마다 지원되는 서비스 유형과 매개변수가 조금씩 다릅니다. [예제] 섹션을 참조하세요.
지원되는 데이터 형식
버전 4.1.4부터는 데이터 파일(split)별로 파일 형식을 결정하므로, Parquet와 ORC 데이터 파일이 함께 있는 단일 Iceberg 테이블도 정상적으로 쿼리할 수 있습니다. 테이블 수준의 write.format.default 속성이 설정되지 않은 경우, 데이터 파일을 조사하여 형식을 추론하는 대신 기본 형식인 parquet을 사용합니다.
버전 4.1.4부터는 모든 split에 Iceberg identity 파티션 메타데이터가 전달되며, 경로 파티션 키에는 모든 파티션 사양에 공통으로 포함된 identity 컬럼만 들어갑니다. 따라서 파티션 진화를 거친 테이블에서도 파티션 컬럼 값이 올바르게 반환됩니다.
컬럼 유형 매핑
Doris 4.2의 전체 매핑 표, 정밀도 규칙, 지원되지 않는 유형에 대해서는 Iceberg에서 Doris로의 데이터 유형 매핑을 참조하세요.
컬럼 이름의 대소문자
Doris는 Iceberg 테이블 컬럼 이름의 원래 대소문자를 보존하고, 읽을 때는 대소문자를 구분하지 않고 컬럼을 매칭합니다. 대문자가 포함되거나 대소문자가 섞인 컬럼 이름(예: UserId 또는 ORDER_ID)도 정상적으로 쿼리할 수 있습니다.
4.0.8 이전 버전에서는 읽을 때 정확히 일치하는 이름으로 컬럼을 찾았으므로, 컬럼 이름에 대소문자가 섞인 Iceberg 및 Paimon 테이블에서 잘못된 컬럼을 읽거나 쿼리가 실패할 수 있었습니다. 이 문제는 4.0.8에서 수정되었습니다.
Namespace 매핑
Iceberg의 메타데이터 계층은 Catalog -> Namespace -> Table입니다. Namespace는 여러 수준으로 구성될 수 있습니다(Nested Namespace).
┌─────────┐
│ Catalog │
└────┬────┘
│
┌─────┴─────┐
┌──▼──┐ ┌──▼──┐
│ NS1 │ │ NS2 │
└──┬──┘ └──┬──┘
│ │
┌────▼───┐ ┌──▼──┐
│ Table1 │ │ NS3 │
└────────┘ └──┬──┘
│
┌──────┴───────┐
┌────▼───┐ ┌────▼───┐
│ Table2 │ │ Table3 │
└────────┘ └────────┘
버전 3.1.2부터 Doris는 Iceberg Rest Catalog에서 Nested Namespace 매핑을 지원합니다.
위 예제의 테이블은 다음 규칙에 따라 Doris 메타데이터로 매핑됩니다.
| Catalog | 데이터베이스 | 테이블 |
|---|---|---|
| Catalog | NS1 | Table1 |
| Catalog | NS2.NS3 | Table2 |
| Catalog | NS2.NS3 | Table3 |
Nested Namespace 지원은 명시적으로 활성화해야 합니다. 자세한 내용은 Iceberg Rest Catalog를 참조하세요.
예제
Hive Metastore
3.1+ 버전
- HDFS
- S3
- OSS
- COS
- OBS
- GCS
- Azure Blob
- Ozone
- MinIO
Kerberos 인증 없이 HMS 및 HDFS 서비스에 접근
CREATE CATALOG iceberg_hms_on_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'hdfs://127.0.0.1:8320/user/iceberg/warehouse/iceberg-hms-hdfs-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'fs.defaultFS' = 'hdfs://127.0.0.1:8320',
'hadoop.username' = 'doris'
);
Kerberos 인증이 활성화된 HMS 및 HDFS 서비스에 접근
CREATE CATALOG iceberg_hms_on_hdfs_kerberos_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'hdfs://127.0.0.1:8520/iceberg-hms-hdfs-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.client.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hive.metastore.client.keytab' = '/keytabs/hive-presto-master.keytab',
'hive.metastore.service.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.authentication.type' = 'kerberos',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal'='hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab'
);
Kerberos 인증 없이 HMS에 접근
CREATE CATALOG iceberg_hms_on_s3_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 's3://selectdb-qa-datalake-test-hk/refactor-test/iceberg-hms-s3-warehouse',
's3.region' = 'ap-east-1',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
IAM Assumed Role을 사용하여 S3 접근 자격 증명 가져오기(3.1.2+)
CREATE CATALOG iceberg_hms_on_s3_iamrole PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 's3://bucket/warehouse',
's3.region' = 'us-east-1',
's3.role_arn' = 'arn:aws:iam::543815668950:role/role'
);
Kerberos 인증 없이 HMS에 접근
CREATE CATALOG iceberg_hms_on_oss_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'oss://bucket/iceberg/iceberg-hms-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
'oss.region' = 'cn-beijing',
'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>'
);
Kerberos 인증이 활성화된 HMS에 접근
CREATE CATALOG iceberg_hms_on_oss_kerberos_new_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'oss://bucket/iceberg/iceberg-hms-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.client.principal' = 'presto-server/presto-master.docker.cluster@LABS.TERADATA.COM',
'hive.metastore.client.keytab' = '/keytabs/presto-server.keytab',
'hive.metastore.authentication.type' = 'kerberos',
'hive.metastore.service.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'oss.region' = 'cn-beijing',
'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>'
);
Kerberos 인증 없이 HMS에 접근
CREATE CATALOG `iceberg_hms_on_cos_catalog` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'cos://bucket/iceberg-hms-cos-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'cos.region' = 'ap-beijing',
'cos.endpoint' = 'cos.ap-beijing.myqcloud.com',
'cos.secret_key' = '<sk>',
'cos.access_key' = '<ak>'
);
Kerberos 인증이 활성화된 HMS에 접근
CREATE CATALOG `iceberg_hms_on_cos_kerberos_new_catalog` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'cos://bucket/iceberg-hms-cos-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.service.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.client.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hive.metastore.client.keytab' = '/keytabs/hive-presto-master.keytab',
'hadoop.security.auth_to_local' = 'RULE:[2:$1@$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:$1@$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:$1@$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'cos.region' = 'ap-beijing',
'cos.endpoint' = 'cos.ap-beijing.myqcloud.com',
'cos.secret_key' = '<sk>',
'cos.access_key' = '<ak>'
);
Kerberos 인증 없이 HMS에 접근
CREATE CATALOG test_iceberg_on_hms_obs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'obs://bucket/regression/iceberg',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'obs.region' = 'cn-north-4',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>'
);
Kerberos 인증이 활성화된 HMS에 접근
CREATE CATALOG obs PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'obs://bucket/regression/iceberg1',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.service.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.client.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hive.metastore.client.keytab' = '/keytabs/hive-presto-master.keytab',
'hive.metastore.authentication.type' = 'kerberos',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'obs.region' = 'cn-north-4',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>'
);
CREATE CATALOG `iceberg_hms_on_gcs_kerberos_new_catalog` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 'gs://bucket/iceberg_warehouse',
'gs.access_key' = '<ak>',
'gs.secret_key' = '<sk>',
'fs.gcs.support' = 'true'
);
3.1.3부터 지원
CREATE CATALOG iceberg_fs_on_azure_blob_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'abfs://<container>@<account_name>.dfs.core.windows.net/iceberg-warehouse',
'azure.account_name' = '<account_name>',
'azure.account_key' = '<account_key>',
'azure.endpoint' = 'https://<account_name>.blob.core.windows.net',
'fs.azure.support' = 'true'
);
4.0.4부터 지원
CREATE CATALOG iceberg_fs_on_ozone_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 's3a://bucket/iceberg_warehouse',
'fs.ozone.support' = 'true',
'ozone.endpoint' = 'http://ozone-s3g:9878',
'ozone.access_key' = '<ak>',
'ozone.secret_key' = '<sk>',
'ozone.region' = 'us-east-1',
'ozone.use_path_style' = 'true'
);
CREATE CATALOG test_iceberg_on_hms_minio_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 's3://warehouse/wh',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'fs.minio.support' = 'true',
'minio.use_path_style' = 'true',
'minio.endpoint' = 'http://127.0.0.1:19001',
'minio.access_key' = '<ak>',
'minio.secret_key' = '<sk>'
);
2.1 & 3.0 버전
- HDFS
- S3
- OSS
- COS
- OBS
- MinIO
Kerberos 인증 없이 HMS 및 HDFS 서비스에 접근
CREATE CATALOG iceberg_hms_on_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 'hdfs://127.0.0.1:8320/user/iceberg/warehouse/iceberg-hms-hdfs-warehouse',
'hadoop.username' = 'doris',
'fs.defaultFS' = 'hdfs://127.0.0.1:8320'
);
Kerberos 인증이 활성화된 HMS 및 HDFS 서비스에 접근
CREATE CATALOG iceberg_hms_on_hdfs_kerberos_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'hdfs://127.0.0.1:8520/iceberg-hms-hdfs-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9583',
'hive.metastore.kerberos.principal' = 'hive/hadoop-master@LABS.TERADATA.COM',
'hive.metastore.sasl.enabled' = 'true',
'hive.metastore.authentication.type' = 'kerberos',
'hadoop.security.auth_to_local' = 'RULE:[2:\$1@\$0](.*@LABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
RULE:[2:\$1@\$0](.*@OTHERREALM.COM)s/@.*//
DEFAULT',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal'='hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab'
);
CREATE CATALOG iceberg_hms_on_s3_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 's3://selectdb-qa-datalake-test-hk/refactor-test/iceberg-hms-s3-warehouse',
's3.region' = 'ap-east-1',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_hms_on_oss_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9083',
'warehouse' = 'oss://bucket/iceberg/iceberg-hms-warehouse',
'oss.region' = 'cn-beijing',
'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>'
);
CREATE CATALOG `iceberg_hms_on_cos_catalog` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 'cos://bucket/iceberg-hms-cos-warehouse',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'cos.region' = 'ap-beijing',
'cos.endpoint' = 'cos.ap-beijing.myqcloud.com',
'cos.secret_key' = '<sk>',
'cos.access_key' = '<ak>'
);
CREATE CATALOG test_iceberg_on_hms_obs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
'warehouse' = 'obs://bucket/regression/iceberg',
'obs.region' = 'cn-north-4',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>'
);
CREATE CATALOG test_iceberg_on_hms_minio_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hms',
'warehouse' = 's3://warehouse/iceberg',
'hive.metastore.uris' = 'thrift://127.0.0.1:9383',
's3.endpoint' = 'http://127.0.0.1:19001',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
AWS Glue
3.1+ 버전
- S3
AWS Glue와 S3 스토리지 서비스는 동일한 인증 자격 증명을 공유합니다.
CREATE CATALOG `iceberg_glue_on_s3_catalog_` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'glue',
'warehouse' = 's3://bucket/iceberg-glue-s3-warehouse',
'glue.region' = 'ap-northeast-1',
'glue.endpoint' = 'https://glue.ap-northeast-1.amazonaws.com',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>'
);
Glue 서비스의 인증 자격 증명과 S3 인증 자격 증명이 다른 경우, 다음 방법으로 S3 인증 자격 증명을 별도로 지정할 수 있습니다.
CREATE CATALOG `iceberg_glue_on_s3_catalog_` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'glue',
'warehouse' = 's3://selectdb-qa-datalake-test/iceberg-glue-s3-warehouse',
'glue.region' = 'ap-northeast-1',
'glue.endpoint' = 'https://glue.ap-northeast-1.amazonaws.com',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>',
's3.endpoint' = 'https://s3.ap-northeast-1.amazonaws.com',
's3.region' = 'ap-northeast-1',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
CREATE CATALOG `glue_iceberg_iamrole` PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'glue',
'warehouse' = 's3://bucket/warehouse',
'glue.region' = 'us-east-1',
'glue.endpoint' = 'https://glue.us-east-1.amazonaws.com',
'glue.role_arn' = '<role_arn>'
);
2.1 & 3.0 버전
- S3
AWS Glue와 S3 스토리지 서비스는 동일한 인증 자격 증명을 공유합니다.
EC2 이외의 환경에서는 aws configure를 사용하여 자격 증명 정보를 구성하고 ~/.aws 디렉터리에 자격 증명 파일을 생성해야 합니다.
CREATE CATALOG glue PROPERTIES (
'type'='iceberg',
'iceberg.catalog.type' = 'glue',
'glue.endpoint' = 'https://glue.us-east-1.amazonaws.com',
'glue.access_key' = '<ak>',
'glue.secret_key' = '<sk>'
);
Aliyun DLF
4.1+ 버전
- DLF 2.5+
CREATE CATALOG iceberg_dlf2_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://<region>-vpc.dlf.aliyuncs.com/iceberg',
'warehouse' = '<your-catalog-name>',
'iceberg.rest.sigv4-enabled' = 'true',
'iceberg.rest.signing-name' = 'DlfNext',
'iceberg.rest.access-key-id' = '<ak>',
'iceberg.rest.secret-access-key' = '<sk>',
'iceberg.rest.signing-region' = '<region>',
'iceberg.rest.vended-credentials-enabled' = 'true',
'io-impl' = 'org.apache.iceberg.rest.DlfFileIO',
'fs.oss.support' = 'true'
);
3.1+ 버전
- DLF 1.0
CREATE CATALOG iceberg_dlf_catalog_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'dlf',
'warehouse' = 'oss://bucket/iceberg-dlf-oss-warehouse',
'dlf.uid' = '203225413946383283',
'dlf.catalog_id' = 'p2_regression_case',
'dlf.region' = 'cn-beijing',
'dlf.endpoint' = 'datalake.cn-beijing.aliyuncs.com',
'dlf.access_key' = '<ak>',
'dlf.secret_key' = '<sk>'
);
2.1 & 3.0 버전
- DLF 1.0
CREATE CATALOG iceberg_dlf_catalog_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'dlf',
'warehouse' = 'oss://bucket/iceberg-dlf-oss-warehouse',
'dlf.uid' = '203225413946383283',
'dlf.catalog.id' = 'catalog_id',
'dlf.region' = 'cn-beijing',
'dlf.access_key' = '<ak>',
'dlf.secret_key' = '<sk>'
);
Iceberg Rest Catalog
버전 4.1.4부터 iceberg.rest.signing-name을 glue, s3tables, osstables와 같은 관리형 서명 서비스로 설정할 때는 'iceberg.rest.sigv4-enabled' = 'true'도 반드시 설정해야 합니다. 그렇지 않으면 다음 오류와 함께 Catalog 생성이 실패합니다.
Rest Catalog requires sigv4-enabled set to true when signing-name is <name>
기존 Catalog에서 signing-name만 설정하고 sigv4-enabled를 활성화하지 않은 경우, 업그레이드 후 검증이 실패하므로 해당 속성을 추가해야 합니다.
Alibaba Cloud OSS Tables
버전 4.1.4부터 지원됩니다.
iceberg.rest.signing-name은 Alibaba Cloud OSS Tables에 연결하기 위한 새 값인 osstables를 지원합니다. 이 경우 REST 요청 서명에는 OSS 자격 증명(oss.access_key, oss.secret_key, oss.session_token)을 재사용하며 s3.* 자격 증명은 사용하지 않습니다.
CREATE CATALOG iceberg_osstables PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = '<oss_tables_rest_endpoint>',
'warehouse' = '<your-catalog-name>',
'iceberg.rest.sigv4-enabled' = 'true',
'iceberg.rest.signing-name' = 'osstables',
'iceberg.rest.signing-region' = '<region>',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>',
'oss.endpoint' = 'oss-<region>.aliyuncs.com',
'oss.region' = '<region>'
);
osstables를 사용할 때는 iceberg.rest.signing-region과 iceberg.rest.sigv4-enabled = 'true'가 모두 필요합니다. 그렇지 않으면 다음 오류가 발생합니다.
Rest Catalog requires signing-region and sigv4-enabled set to true when signing-name is osstables
3.1+ 버전
- S3
- OSS
- COS
- OBS
- GCS
- HDFS
- 인증 없음
- OAuth2 인증
- 발급된 자격 증명
CREATE CATALOG iceberg_static_s3 PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'ap-east-1'
);
CREATE CATALOG polaris_oauth2_credential_static_s3 PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'doris_test',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181/api/catalog',
'iceberg.rest.security.type' = 'oauth2',
'iceberg.rest.oauth2.credential' = 'root:secret123',
'iceberg.rest.oauth2.server-uri' = 'http://127.0.0.1:8181/api/catalog/v1/oauth/tokens',
'iceberg.rest.oauth2.scope' = 'PRINCIPAL_ROLE:ALL',
's3.endpoint' = 'https://s3.us-west-2.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'us-west-2'
);
CREATE CATALOG gravitino_vended_s3 PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:9001/iceberg/',
'iceberg.rest.vended-credentials-enabled' = 'true'
);
- 인증 없음
- OAuth2 인증
CREATE CATALOG iceberg_static_oss PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
'oss.endpoint' = 'https://oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>',
'oss.region' = 'cn-beijing'
);
CREATE CATALOG polaris_oauth2_credential_static_oss PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'doris_test',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181/api/catalog',
'iceberg.rest.security.type' = 'oauth2',
'iceberg.rest.oauth2.credential' = 'root:secret123',
'iceberg.rest.oauth2.server-uri' = 'http://127.0.0.1:8181/api/catalog/v1/oauth/tokens',
'iceberg.rest.oauth2.scope' = 'PRINCIPAL_ROLE:ALL',
'oss.endpoint' = 'https://oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>',
'oss.region' = 'cn-beijing'
);
- 인증 없음
- OAuth2 인증
CREATE CATALOG iceberg_static_cos PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
'cos.endpoint' = 'https://cos.ap-beijing.myqcloud.com',
'cos.access_key' = '<ak>',
'cos.secret_key' = '<sk>',
'cos.region' = 'ap-beijing'
);
CREATE CATALOG polaris_oauth2_credential_static_cos PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'doris_test',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181/api/catalog',
'iceberg.rest.security.type' = 'oauth2',
'iceberg.rest.oauth2.credential' = 'root:secret123',
'iceberg.rest.oauth2.server-uri' = 'http://127.0.0.1:8181/api/catalog/v1/oauth/tokens',
'iceberg.rest.oauth2.scope' = 'PRINCIPAL_ROLE:ALL',
'cos.endpoint' = 'https://cos.ap-beijing.myqcloud.com',
'cos.access_key' = '<ak>',
'cos.secret_key' = '<sk>',
'cos.region' = 'ap-beijing'
);
- 인증 없음
- OAuth2 인증
CREATE CATALOG iceberg_static_obs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>',
'obs.region' = 'cn-north-4'
);
CREATE CATALOG polaris_oauth2_credential_static_obs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'doris_test',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181/api/catalog',
'iceberg.rest.security.type' = 'oauth2',
'iceberg.rest.oauth2.credential' = 'root:secret123',
'iceberg.rest.oauth2.server-uri' = 'http://127.0.0.1:8181/api/catalog/v1/oauth/tokens',
'iceberg.rest.oauth2.scope' = 'PRINCIPAL_ROLE:ALL',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>',
'obs.region' = 'cn-north-4'
);
- 인증 없음
- OAuth2 인증
CREATE CATALOG iceberg_static_gcs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'gs://warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
'gs.endpoint' = 'https://storage.googleapis.com',
'gs.access_key' = '<ak>',
'gs.secret_key' = '<sk>'
);
CREATE CATALOG polaris_oauth2_credential_static_gcs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'doris_test',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181/api/catalog',
'iceberg.rest.security.type' = 'oauth2',
'iceberg.rest.oauth2.credential' = 'root:secret123',
'iceberg.rest.oauth2.server-uri' = 'http://127.0.0.1:8181/api/catalog/v1/oauth/tokens',
'iceberg.rest.oauth2.scope' = 'PRINCIPAL_ROLE:ALL',
'gs.endpoint' = 'https://storage.googleapis.com',
'gs.access_key' = '<ak>',
'gs.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_static_hdfs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'hdfs://127.0.0.1:8020/user/iceberg/warehouse',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'http://127.0.0.1:8181',
'fs.defaultFS' = 'hdfs://127.0.0.1:8020'
);
2.1 & 3.0 버전
- S3
- OSS
- COS
- OBS
- HDFS
CREATE CATALOG iceberg_static_s3 PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'uri' = 'http://127.0.0.1:8181',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'ap-east-1'
);
CREATE CATALOG iceberg_static_oss PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'uri' = 'http://127.0.0.1:8181',
's3.endpoint' = 'https://oss-cn-beijing.aliyuncs.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'cn-beijing'
);
CREATE CATALOG iceberg_static_cos PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'uri' = 'http://127.0.0.1:8181',
's3.endpoint' = 'https://cos.ap-beijing.myqcloud.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'ap-beijing'
);
CREATE CATALOG iceberg_static_obs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 's3://warehouse',
'iceberg.catalog.type' = 'rest',
'uri' = 'http://127.0.0.1:8181',
's3.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.region' = 'cn-north-4'
);
CREATE CATALOG iceberg_static_hdfs PROPERTIES (
'type' = 'iceberg',
'warehouse' = 'hdfs://127.0.0.1:8020/user/iceberg/warehouse',
'iceberg.catalog.type' = 'rest',
'uri' = 'http://127.0.0.1:8181',
'fs.defaultFS' = 'hdfs://127.0.0.1:8020'
);
Iceberg JDBC Catalog
실험적 기능으로, 버전 4.1.0부터 지원됩니다.
4.1+ 버전
- PostgreSQL
- MySQL
- SQLite
PostgreSQL을 메타데이터 스토리지로 사용하고 S3와 함께 구성
CREATE CATALOG iceberg_jdbc_postgresql PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'jdbc',
'iceberg.jdbc.catalog_name' = 'iceberg_jdbc_postgresql',
'iceberg.jdbc.uri' = 'jdbc:postgresql://127.0.0.1:5432/iceberg_db',
'iceberg.jdbc.user' = 'iceberg_user',
'iceberg.jdbc.password' = 'password',
'iceberg.jdbc.init-catalog-tables' = 'true',
'iceberg.jdbc.schema-version' = 'V1',
'iceberg.jdbc.driver_class' = 'org.postgresql.Driver',
'iceberg.jdbc.driver_url' = '<jdbc_driver_jar>',
'warehouse' = 's3://bucket/warehouse',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.endpoint' = 'https://s3.us-east-1.amazonaws.com',
's3.region' = 'us-east-1'
);
MySQL을 메타데이터 스토리지로 사용하고 S3와 함께 구성
CREATE CATALOG iceberg_jdbc_mysql PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'jdbc',
'iceberg.jdbc.catalog_name' = 'iceberg_jdbc_mysql',
'iceberg.jdbc.uri' = 'jdbc:mysql://127.0.0.1:3306/iceberg_db',
'iceberg.jdbc.user' = 'iceberg_user',
'iceberg.jdbc.password' = 'password',
'iceberg.jdbc.init-catalog-tables' = 'true',
'iceberg.jdbc.schema-version' = 'V1',
'iceberg.jdbc.driver_class' = 'com.mysql.cj.jdbc.Driver',
'iceberg.jdbc.driver_url' = '<jdbc_driver_jar>',
'warehouse' = 's3://bucket/warehouse',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.endpoint' = 'https://s3.us-east-1.amazonaws.com',
's3.region' = 'us-east-1'
);
SQLite를 메타데이터 스토리지로 사용(테스트 환경에 적합)
CREATE CATALOG iceberg_jdbc_sqlite PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'jdbc',
'iceberg.jdbc.catalog_name' = 'iceberg_jdbc_sqlite',
'iceberg.jdbc.uri' = 'jdbc:sqlite:/tmp/iceberg_catalog.db',
'iceberg.jdbc.init-catalog-tables' = 'true',
'iceberg.jdbc.schema-version' = 'V1',
'iceberg.jdbc.driver_class' = 'org.sqlite.JDBC',
'iceberg.jdbc.driver_url' = '<jdbc_driver_jar>',
'warehouse' = 's3://bucket/warehouse',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>',
's3.endpoint' = 'https://s3.us-east-1.amazonaws.com',
's3.region' = 'us-east-1'
);
FileSystem
3.1+ 버전
- HDFS
- S3
- COS
- OSS
- OBS
- GCS
- MinIO
Kerberos 인증 없이 HDFS 서비스에 접근
CREATE CATALOG iceberg_fs_on_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'hdfs://127.0.0.1:8320/user/iceberg/warehouse/iceberg-fs-hdfs-warehouse',
'hadoop.username' = 'doris',
'fs.defaultFS' = 'hdfs://127.0.0.1:8320'
);
Kerberos 인증이 활성화된 HDFS 서비스에 접근
CREATE CATALOG iceberg_fs_on_hdfs_kerberos_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'hdfs://127.0.0.1:8520/iceberg-fs-hdfs-warehouse',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal' = 'hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab'
);
CREATE CATALOG iceberg_fs_on_glue_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 's3://selectdb-qa-datalake-test-hk/refactor-test/iceberg-fs-s3-warehouse',
's3.region' = 'ap-east-1',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
IAM Assumed Role을 사용하여 S3 접근 자격 증명 가져오기(3.1.2+)
CREATE CATALOG iceberg_fs_on_s3_iamrole PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 's3://bucket/warehouse',
's3.region' = 'us-east-1',
's3.role_arn' = 'arn:aws:iam::543815668950:role/role'
);
CREATE CATALOG iceberg_fs_on_cos_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'cos://doris-build-1308700295/iceberg-fs-cos-warehouse',
'cos.region' = 'ap-beijing',
'cos.endpoint' = 'cos.ap-beijing.myqcloud.com',
'cos.access_key' = '<ak>',
'cos.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_fs_on_oss_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'oss://doris-regression-bj/refactor-test/iceberg-fs-oss-warehouse',
'oss.region' = 'cn-beijing',
'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>'
);
CREATE CATALOG test_fs_on_obs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'obs://bucket/regression/iceberg',
'obs.region' = 'cn-north-4',
'obs.endpoint' = 'obs.cn-north-4.myhuaweicloud.com',
'obs.access_key' = '<ak>',
'obs.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_fs_on_gcs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'gs://bucket/iceberg_warehouse',
'fs.gcs.support' = 'true',
'gs.access_key' = '<ak>',
'gs.secret_key' = '<sk>'
);
CREATE CATALOG test_iceberg_fs_on_minio PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 's3://warehouse/wh',
'fs.minio.support' = 'true',
'minio.endpoint' = 'http://127.0.0.1:19001',
'minio.access_key' = 'admin',
'minio.secret_key' = 'password',
'minio.use_path_style' = 'true'
);
2.1 & 3.0 버전
- HDFS
- S3
- COS
- OSS
- GCS
- MinIO
Kerberos 인증 없이 HDFS 서비스에 접근
CREATE CATALOG iceberg_fs_on_hdfs_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'hdfs://127.0.0.1:8320/user/iceberg/warehouse/iceberg-fs-hdfs-warehouse',
'hadoop.username' = 'doris',
'fs.defaultFS' = 'hdfs://127.0.0.1:8320'
);
Kerberos 인증이 활성화된 HDFS 서비스에 접근
CREATE CATALOG iceberg_fs_on_hdfs_kerberos_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'hdfs://127.0.0.1:8520/iceberg-fs-hdfs-warehouse',
'fs.defaultFS' = 'hdfs://127.0.0.1:8520',
'hadoop.security.authentication' = 'kerberos',
'hadoop.kerberos.principal'='hive/presto-master.docker.cluster@LABS.TERADATA.COM',
'hadoop.kerberos.keytab' = '/keytabs/hive-presto-master.keytab'
);
CREATE CATALOG iceberg_fs_on_s3_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 's3://selectdb-qa-datalake-test-hk/refactor-test/iceberg-fs-s3-warehouse',
's3.region' = 'ap-east-1',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_fs_on_cos_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'cos://doris-build-1308700295/iceberg-fs-cos-warehouse',
'cos.region' = 'ap-beijing',
'cos.endpoint' = 'cos.ap-beijing.myqcloud.com',
'cos.access_key' = '<ak>',
'cos.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_fs_on_oss_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'hadoop',
'warehouse' = 'oss://bucket/refactor-test/iceberg-fs-oss-warehouse',
'oss.region' = 'cn-beijing',
'oss.endpoint' = 'oss-cn-beijing.aliyuncs.com',
'oss.access_key' = '<ak>',
'oss.secret_key' = '<sk>'
);
CREATE CATALOG iceberg_fs_on_gcs_catalog PROPERTIES (
'type'='iceberg',
'iceberg.catalog.type'='hadoop',
'warehouse' = 's3://bucket/iceberg_warehouse',
'gs.endpoint'='storage.googleapis.com',
'gs.access_key' = '<ak>',
'gs.secret_key' = '<sk>'
);
CREATE CATALOG test_iceberg_fs_on_minio PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type'='hadoop',
'warehouse' = 's3://warehouse/wh',
's3.region' = 'ap-east-1',
's3.endpoint' = 'http://minio:9000',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
AWS S3 Tables
3.1+ 버전
- S3 Tables Rest Catalog
- AWS Glue Rest Catalog
- FileSystem Catalog
S3 Tables 통합 문서를 참조하세요.
CREATE CATALOG aws_s3_tables PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'rest',
'warehouse' = 'arn:aws:s3tables:us-east-1:<account_id>:bucket/<s3_table_bucket_name>',
'iceberg.rest.uri' = 'https://s3tables.us-east-1.amazonaws.com/iceberg',
'iceberg.rest.sigv4-enabled' = 'true',
'iceberg.rest.signing-name' = 's3tables',
'iceberg.rest.signing-region' = 'us-east-1',
'iceberg.rest.access-key-id' = '<ak>',
'iceberg.rest.secret-access-key' = '<sk>'
);
S3 Tables 통합 문서를 참조하세요.
CREATE CATALOG glue_s3 PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'https://glue.ap-east-1.amazonaws.com/iceberg',
'warehouse' = '<acount_id>:s3tablescatalog/<s3_table_bucket_name>',
'iceberg.rest.sigv4-enabled' = 'true',
'iceberg.rest.signing-name' = 'glue',
'iceberg.rest.access-key-id' = '<ak>',
'iceberg.rest.secret-access-key' = '<sk>',
'iceberg.rest.signing-region' = 'ap-east-1'
);
S3 Tables 통합 문서를 참조하세요.
CREATE CATALOG test_s3tables_write_insert PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 's3tables',
'warehouse' = 'arn:aws:s3tables:ap-east-1:12345:bucket/doris-s3-table-bucket',
's3.region' = 'ap-east-1',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
3.0.6+ 버전
- FileSystem Catalog
S3 Tables 통합 문서를 참조하세요.
CREATE CATALOG test_s3tables_catalog PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 's3tables',
'warehouse' = 'arn:aws:s3tables:ap-east-1:9527:bucket/doris-s3-table-bucket',
's3.region' = 'ap-east-1',
's3.endpoint' = 'https://s3.ap-east-1.amazonaws.com',
's3.access_key' = '<ak>',
's3.secret_key' = '<sk>'
);
Alibaba Cloud OSS Tables
4.1.4+ 버전
- OSS Tables REST Catalog
전체 구성 및 사용 방법은 Alibaba Cloud OSS Tables 통합을 참조하세요.
CREATE CATALOG oss_tables PROPERTIES (
'type' = 'iceberg',
'iceberg.catalog.type' = 'rest',
'iceberg.rest.uri' = 'https://<region>.oss-tables.aliyuncs.com/iceberg',
'warehouse' = 'acs:osstables:<region>:<account_id>:bucket/<table_bucket_name>',
'iceberg.rest.sigv4-enabled' = 'true',
'iceberg.rest.signing-name' = 'osstables',
'iceberg.rest.signing-region' = '<region>',
'iceberg.rest.view-enabled' = 'false',
'io-impl' = 'org.apache.iceberg.aws.s3.S3FileIO',
'oss.endpoint' = 'https://oss-<region>.aliyuncs.com',
'oss.region' = '<region>',
'oss.access_key' = '<access_key_id>',
'oss.secret_key' = '<access_key_secret>',
'oss.use_path_style' = 'false',
'test_connection' = 'true'
);
쿼리 작업
기본 쿼리
-- 1. switch to catalog, use database and query
SWITCH iceberg;
USE iceberg_db;
SELECT * FROM iceberg_tbl LIMIT 10;
-- 2. use iceberg database directly
USE iceberg.iceberg_db;
SELECT * FROM iceberg_tbl LIMIT 10;
-- 3. use full qualified name to query
SELECT * FROM iceberg.iceberg_db.iceberg_tbl LIMIT 10;
타임 트래블
Iceberg 테이블의 특정 스냅샷을 읽을 수 있습니다.
기본적으로 읽기 요청은 최신 스냅샷 버전에 접근합니다.
$snapshots 시스템 테이블을 사용하여 Iceberg 테이블의 스냅샷을 쿼리할 수 있습니다.
버전 4.1.4부터 iceberg_meta() 테이블 함수가 제거되었습니다. 대신 Iceberg 시스템 테이블(예: iceberg_tbl$snapshots)을 사용하여 메타데이터를 쿼리하세요. 아래 시스템 테이블 섹션을 참조하세요.
SELECT * FROM iceberg_ctl.iceberg_db.iceberg_tbl$snapshots\G
*************************** 1. row ***************************
committed_at: 2024-11-28 11:07:29
snapshot_id: 8903826400153112036
parent_id: -1
operation: append
manifest_list: oss://path/to/metadata/snap-8903826400153112036-1-3835e66d-9a18-4cb0-b9b0-9ec80527ad8d.avro
summary: {"added-data-files":"2","added-records":"3","added-files-size":"2742","changed-partition-count":"2","total-records":"3","total-files-size":"2742","total-data-files":"2","total-delete-files":"0","total-position-deletes":"0","total-equality-deletes":"0"}
*************************** 2. row ***************************
committed_at: 2024-11-28 11:10:11
snapshot_id: 6099853805930794326
parent_id: 8903826400153112036
operation: append
manifest_list: oss://path/to/metadata/snap-6099853805930794326-1-dd46a1bd-219b-4fb0-bb46-ac441d8b3105.avro
summary: {"added-data-files":"1","added-records":"1","added-files-size":"1367","changed-partition-count":"1","total-records":"4","total-files-size":"4109","total-data-files":"3","total-delete-files":"0","total-position-deletes":"0","total-equality-deletes":"0"}
FOR TIME AS OF 및 FOR VERSION AS OF 절을 사용하면 스냅샷 ID 또는 스냅샷 생성 시각을 기준으로 과거 데이터를 읽을 수 있습니다. 다음은 몇 가지 예입니다.
-- Read data as of a specific timestamp
SELECT * FROM iceberg_table FOR TIME AS OF '2023-01-01 00:00:00';
-- Read data as of a specific snapshot ID
SELECT * FROM iceberg_table FOR VERSION AS OF 123456789;
4.1.5부터 FOR TIME AS OF는 yyyy-MM-dd HH:mm:ss 뒤에 1~9자리의 소수 초를 허용하며, 값을 세션 시간대로 해석한 후 밀리초로 변환하여 스냅샷을 선택합니다. 예를 들어 FOR TIME AS OF '2024-01-01 12:00:00.123456'를 사용할 수 있습니다. 스냅샷 선택 정밀도는 밀리초입니다. 이 구문을 허용한다고 해서 나노초 단위의 스냅샷 시각이 보존되는 것은 아닙니다.
Doris 4.1.5에서는 컬럼 이름 변경, 삭제, 유형 승격, 파티션 진화 이후의 과거 스냅샷 읽기도 수정되었습니다. 각 파일은 현재 파티션 사양만 사용하는 대신 작성 당시 적용되던 파티션 사양으로 해석됩니다. 과거 데이터를 조회하는 쿼리는 현재 구체화된 뷰를 읽도록 재작성되어서는 안 됩니다.
브랜치와 태그
3.1.0부터 지원됩니다.
브랜치와 태그의 생성, 삭제 및 관리는 [브랜치 및 태그 관리] 섹션을 참조하세요.
Iceberg 테이블의 특정 브랜치와 태그 읽기를 지원합니다.
Spark/Trino 등의 시스템과 호환되도록 여러 구문 형식을 지원합니다.
-- BRANCH
SELECT * FROM iceberg_tbl@branch(branch1);
SELECT * FROM iceberg_tbl@branch("name" = "branch1");
SELECT * FROM iceberg_tbl FOR VERSION AS OF 'branch1';
-- TAG
SELECT * FROM iceberg_tbl@tag(tag1);
SELECT * FROM iceberg_tbl@tag("name" = "tag1");
SELECT * FROM iceberg_tbl FOR VERSION AS OF 'tag1';
FOR VERSION AS OF 구문에서는 Doris가 매개변수가 타임스탬프인지 브랜치/태그 이름인지 자동으로 판단합니다.
뷰
3.1.0부터 지원
Iceberg 뷰 쿼리를 지원합니다. 뷰 쿼리는 일반 테이블 쿼리와 동일하게 작동합니다. 다음 사항에 유의하세요.
hms유형의 Iceberg Catalog만 지원합니다.- 뷰 정의 SQL은 Doris SQL 방언과 호환되어야 하며, 그렇지 않으면 구문 분석 오류가 발생합니다(방언 변환 기능은 향후 버전에서 제공될 예정입니다).
Iceberg V3 숨겨진 컬럼(Row Lineage)
실험적 기능으로, 버전 4.1.0부터 지원됩니다.
Doris는 Iceberg V3 테이블의 Row Lineage 숨겨진 컬럼 쿼리를 지원합니다. Iceberg V3에는 데이터 변경 기록을 추적하는 데 쓰이는 행 계보 데이터가 담긴 시스템 숨겨진 컬럼이 도입되었습니다. 증분 동기화나 데이터 감사에 적합합니다.
_row_id: 데이터 행을 고유하게 식별하는 숫자 값입니다(데이터가 기록된 파일과 위치를 기반으로 생성됨)._last_updated_sequence_number: 이 행이 마지막으로 수정된 Sequence Number입니다.UPDATE또는MERGE INTO작업으로 데이터를 갱신하면 이 숫자 값은 버전 번호와 함께 자동으로 증가합니다.
숨겨진 컬럼 쿼리 방법:
기본적으로 숨겨진 컬럼은 DESC 또는 SELECT *를 사용할 때 표시되지 않습니다. 컬럼 이름을 직접 지정하여 명시적으로 쿼리할 수 있습니다.
SELECT id, _row_id, _last_updated_sequence_number FROM iceberg_tbl;
숨겨진 컬럼을 일반적인 표시 결과(예: DESC 및 SELECT *)에도 포함하려면 세션 변수 show_hidden_columns를 활성화하면 됩니다.
SET show_hidden_columns = true;
DESC iceberg_tbl;
참고 사항:
- 이러한 행 수준 매개변수가 생성되려면 Iceberg 테이블의 형식 버전(
format-version)을3으로 구성해야 합니다. V1 및 V2 형식 테이블에서 행 계보 컬럼을 쿼리하면 오류가 발생할 수 있습니다. - 숨겨진 컬럼은 시스템이 관리합니다. 사용자는
_row_id또는_last_updated_sequence_number컬럼을INSERT와 같은 쓰기 문에서 명시적으로 지정하거나 해당 컬럼에 쓸 수 없습니다. 버전 4.1.4부터는INSERT문의 컬럼 목록에 행 계보 컬럼을 지정하면,format-version >= 3인 테이블에서Cannot specify row lineage column '<name>' in INSERT statement오류와 함께 즉시 실패합니다.
Iceberg V3 기본값
버전 4.1.4부터 지원됩니다.
Iceberg V3는 두 종류의 컬럼 기본값을 정의하며, Doris는 두 종류 모두 지원합니다.
initial-default: 컬럼이 추가될 때 기존 과거 데이터에 부여되는 기본값입니다. 컬럼이 존재하기 전에 작성된 이전 데이터 파일을 읽을 때 Doris는 NULL 대신 이 기본값을 반환합니다. Parquet와 ORC 모두에서 지원하며, 최상위 컬럼,STRUCT내부의 중첩 하위 필드, 전체가 누락된 복합 상위 컬럼에 적용됩니다. 조건식 평가 시에도 적용됩니다.write-default: 쓰기 시 지정되지 않은 컬럼에 채워지는 기본값입니다.INSERT INTO t (subset of columns) VALUES (...)를 사용하면 목록에 없는 컬럼에는 현재write-default가 기록됩니다(이전 버전에서는 NULL을 기록함).
DDL로 기본값 지정:
ALTER TABLE iceberg_tbl ADD COLUMN c1 INT DEFAULT 10;
이 문은 Iceberg의 write-default와 initial-default를 모두 설정합니다. 테이블의 format-version이 3이어야 합니다. V1 및 V2 테이블은 NULL이 아닌 기본값이 있는 컬럼을 지원하지 않습니다.
DEFAULT() 표현식:
버전 4.1.4부터 DML에서 컬럼의 기본값을 명시적으로 참조할 수 있는 DEFAULT(<column>) 표현식을 사용할 수 있습니다. INSERT, UPDATE ... SET, MERGE INTO의 각 분기에서 사용할 수 있습니다.
INSERT INTO iceberg_tbl VALUES (1, DEFAULT(c1));
UPDATE iceberg_tbl SET c1 = DEFAULT(c1) WHERE id = 1;
MERGE INTO iceberg_tbl t USING src s ON t.id = s.id
WHEN NOT MATCHED THEN INSERT VALUES (s.id, DEFAULT(c1));
동작 의미:
- 대상이 Iceberg 테이블인 경우
DEFAULT()는 이번 쓰기에 고정된 Iceberg 스키마를 기준으로 해석됩니다. 쓰기 대상에 속하지 않는 컬럼을 참조하면DEFAULT(<col>) must reference a column in the pinned Iceberg write target오류가 발생합니다. - Iceberg 이외의 컬럼에는 해당 컬럼의 기본값을 사용합니다. 컬럼에 기본값이 없고 NOT NULL이거나 자동 증가 컬럼이면
Column '<name>' has no default value and does not allow NULL or column is auto-increment오류가 발생합니다. NULL을 허용하는 컬럼에 기본값이 없으면 NULL을 사용합니다. - 기타 오류:
DEFAULT requires a column reference, but got: <expr>,Cannot find column information for DEFAULT(<name>),DEFAULT cannot be used on generated column '<name>'.
Iceberg의 write-default는 쓰기 측 커넥터의 개념입니다. DESCRIBE, SHOW CREATE TABLE, information_schema.columns.COLUMN_DEFAULT에는 노출되지 않습니다.
시스템 테이블
3.1.0부터 지원
Doris는 Iceberg 시스템 테이블을 쿼리하여 테이블의 메타데이터 정보를 가져오는 기능을 지원합니다. 시스템 테이블을 사용하면 스냅샷 이력, manifest 파일, 데이터 파일, 파티션 및 기타 메타데이터를 확인할 수 있습니다.
Iceberg 테이블의 메타데이터에 접근하려면 테이블 이름 뒤에 $ 기호와 시스템 테이블 이름을 붙입니다.
SELECT * FROM iceberg_table$system_table_name;
예를 들어 테이블의 이력을 보려면 다음을 실행합니다.
SELECT * FROM iceberg_table$history;
all_manifests시스템 테이블은 버전 4.0.4부터 지원됩니다.
position_deletes시스템 테이블은 버전 4.1.4부터 지원됩니다.
버전 4.1.4부터 Iceberg 시스템 테이블은 네이티브 실행 경로(FileQueryScanNode -> IcebergScanNode)로 쿼리되며, iceberg_meta() 테이블 함수는 제거되었습니다. 대신 <table>$<system_table_name> 시스템 테이블 구문을 사용하세요. ICEBERG_META를 참조하세요.
시스템 테이블 자체의 접근 구문과 반환 결과는 변경되지 않았습니다. 또한 시스템 테이블에서 이제 SHOW CREATE TABLE을 지원합니다.
entries
테이블의 현재 스냅샷에 있는 모든 manifest 항목을 표시합니다.
all_entries와 entries는 유사하지만, all_entries는 모든 스냅샷의 항목을 포함하고 entries는 현재 스냅샷의 항목만 포함한다는 차이가 있습니다.
SELECT * FROM iceberg_table$entries;
결과:
+--------+---------------------+-----------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| status | snapshot_id | sequence_number | file_sequence_number | data_file | readable_metrics |
+--------+---------------------+-----------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 2 | 4890031351138056789 | 1 | 1 | {"content":0, "file_path":"s3://.../iceberg_table/data/id=1/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00001.parquet", "file_format":"PARQUET", "spec_id":0, "partition":{"id":1}, "record_count":1, "file_size_in_bytes":625, "column_sizes":{1:36, 2:41}, "value_counts":{1:1, 2:1}, "null_value_counts":{1:0, 2:0}, "nan_value_counts":{}, "lower_bounds":{1:" ", 2:"Alice"}, "upper_bounds":{1:" ", 2:"Alice"}, "key_metadata":null, "split_offsets":[4], "equality_ids":null, "sort_order_id":0, "first_row_id":null, "referenced_data_file":null, "content_offset":null, "content_size_in_bytes":null} | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":1, "upper_bound":1}, "name":{"column_size":41, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Alice", "upper_bound":"Alice"}} |
| 0 | 1851184769713369003 | 1 | 1 | {"content":0, "file_path":"s3://.../iceberg_table/data/id=2/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00002.parquet", "file_format":"PARQUET", "spec_id":0, "partition":{"id":2}, "record_count":1, "file_size_in_bytes":611, "column_sizes":{1:36, 2:39}, "value_counts":{1:1, 2:1}, "null_value_counts":{1:0, 2:0}, "nan_value_counts":{}, "lower_bounds":{1:" ", 2:"Bob"}, "upper_bounds":{1:" ", 2:"Bob"}, "key_metadata":null, "split_offsets":[4], "equality_ids":null, "sort_order_id":0, "first_row_id":null, "referenced_data_file":null, "content_offset":null, "content_size_in_bytes":null} | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":2, "upper_bound":2}, "name":{"column_size":39, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Bob", "upper_bound":"Bob"}} |
+--------+---------------------+-----------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
files
테이블의 현재 스냅샷에 있는 파일 목록을 표시합니다.
SELECT * FROM iceberg_table$files;
결과:
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------+---------+-----------+--------------+--------------------+--------------+--------------+-------------------+------------------+-----------------------+-----------------------+--------------+---------------+--------------+---------------+--------------+----------------------+----------------+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| content | file_path | file_format | spec_id | partition | record_count | file_size_in_bytes | column_sizes | value_counts | null_value_counts | nan_value_counts | lower_bounds | upper_bounds | key_metadata | split_offsets | equality_ids | sort_order_id | first_row_id | referenced_data_file | content_offset | content_size_in_bytes | readable_metrics |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------+---------+-----------+--------------+--------------------+--------------+--------------+-------------------+------------------+-----------------------+-----------------------+--------------+---------------+--------------+---------------+--------------+----------------------+----------------+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 0 | s3://.../iceberg_table/data/id=2/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00002.parquet | PARQUET | 0 | {"id":2} | 1 | 611 | {1:36, 2:39} | {1:1, 2:1} | {1:0, 2:0} | {} | {1:" ", 2:"Bob"} | {1:" ", 2:"Bob"} | NULL | [4] | NULL | 0 | NULL | NULL | NULL | NULL | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":2, "upper_bound":2}, "name":{"column_size":39, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Bob", "upper_bound":"Bob"}} |
| 0 | s3://.../iceberg_table/data/id=4/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00004.parquet | PARQUET | 0 | {"id":4} | 1 | 618 | {1:36, 2:40} | {1:1, 2:1} | {1:0, 2:0} | {} | {1:" ", 2:"Dave"} | {1:" ", 2:"Dave"} | NULL | [4] | NULL | 0 | NULL | NULL | NULL | NULL | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":4, "upper_bound":4}, "name":{"column_size":40, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Dave", "upper_bound":"Dave"}} |
| 0 | s3://.../iceberg_table/data/id=6/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00006.parquet | PARQUET | 0 | {"id":6} | 1 | 625 | {1:36, 2:41} | {1:1, 2:1} | {1:0, 2:0} | {} | {1:" ", 2:"Frank"} | {1:" ", 2:"Frank"} | NULL | [4] | NULL | 0 | NULL | NULL | NULL | NULL | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":6, "upper_bound":6}, "name":{"column_size":41, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Frank", "upper_bound":"Frank"}} |
| 0 | s3://.../iceberg_table/data/id=8/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00008.parquet | PARQUET | 0 | {"id":8} | 1 | 625 | {1:36, 2:41} | {1:1, 2:1} | {1:0, 2:0} | {} | {1:" ", 2:"Heidi"} | {1:" ", 2:"Heidi"} | NULL | [4] | NULL | 0 | NULL | NULL | NULL | NULL | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":8, "upper_bound":8}, "name":{"column_size":41, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Heidi", "upper_bound":"Heidi"}} |
| 0 | s3://.../iceberg_table/data/id=10/00000-16-79ef2fd7-9997-47eb-a91a-9f7af8201315-0-00010.parquet | PARQUET | 0 | {"id":10} | 1 | 618 | {1:36, 2:40} | {1:1, 2:1} | {1:0, 2:0} | {} | {1:" ", 2:"Judy"} | {1:" ", 2:"Judy"} | NULL | [4] | NULL | 0 | NULL | NULL | NULL | NULL | {"id":{"column_size":36, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":10, "upper_bound":10}, "name":{"column_size":40, "value_count":1, "null_value_count":0, "nan_value_count":null, "lower_bound":"Judy", "upper_bound":"Judy"}} |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------+---------+-----------+--------------+--------------------+--------------+--------------+-------------------+------------------+-----------------------+-----------------------+--------------+---------------+--------------+---------------+--------------+----------------------+----------------+-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
files 시스템 테이블과 유사하게, 다음 시스템 테이블로 특정 파일 유형의 정보도 쿼리할 수 있습니다.
-- Query data files for the current snapshot
SELECT * FROM iceberg_table$data_files;
-- Query delete files for the current snapshot
SELECT * FROM iceberg_table$delete_files;
-- Query all files (including data and delete files) from all snapshots
SELECT * FROM iceberg_table$all_files;
-- Query data files from all snapshots
SELECT * FROM iceberg_table$all_data_files;
-- Query delete files from all snapshots
SELECT * FROM iceberg_table$all_delete_files;
이 테이블의 결과 형식은 files 시스템 테이블과 유사하지만, 각각 데이터 파일 또는 삭제 파일에 초점을 맞춥니다. all_ 접두사가 붙은 시스템 테이블은 현재 스냅샷뿐 아니라 모든 스냅샷의 파일을 포함합니다.
참고: 테이블에 특정 유형의 파일이 없는 경우(예: 삭제 파일이 없는 테이블에서 delete_files를 쿼리하는 경우), 쿼리 결과가 비어 있을 수 있습니다.
history
테이블의 전체 이력을 표시합니다.
SELECT * FROM iceberg_table$history;
결과:
+----------------------------+---------------------+---------------------+---------------------+
| made_current_at | snapshot_id | parent_id | is_current_ancestor |
+----------------------------+---------------------+---------------------+---------------------+
| 2025-06-12 22:29:16.357000 | 1851184769713369003 | NULL | 1 |
| 2025-06-12 22:29:39.922000 | 4890031351138056789 | 1851184769713369003 | 1 |
+----------------------------+---------------------+---------------------+---------------------+
manifests
테이블의 manifest 파일 정보를 표시합니다.
SELECT * FROM iceberg_table$manifests;
결과:
+---------+------------------------------------------------------------------------------------------------------------------------------------------------+--------+-------------------+---------------------+------------------------+---------------------------+--------------------------+--------------------------+-----------------------------+----------------------------+--------------------------------------------------------------------------------+
| content | path | length | partition_spec_id | added_snapshot_id | added_data_files_count | existing_data_files_count | deleted_data_files_count | added_delete_files_count | existing_delete_files_count | deleted_delete_files_count | partition_summaries |
+---------+------------------------------------------------------------------------------------------------------------------------------------------------+--------+-------------------+---------------------+------------------------+---------------------------+--------------------------+--------------------------+-----------------------------+----------------------------+--------------------------------------------------------------------------------+
| 0 | s3://.../iceberg_table/metadata/3194eb8b-5ea4-4cbe-95ba-073229458e7b-m0.avro | 7138 | 0 | 4890031351138056789 | 0 | 5 | 5 | 0 | 0 | 0 | [{"contains_null":0, "contains_nan":0, "lower_bound":"1", "upper_bound":"10"}] |
+---------+------------------------------------------------------------------------------------------------------------------------------------------------+--------+-------------------+---------------------+------------------------+---------------------------+--------------------------+--------------------------+-----------------------------+----------------------------+--------------------------------------------------------------------------------+
all_manifests
이 기능은 버전 4.0.4부터 지원됩니다.
테이블의 모든 유효한 스냅샷에 있는 manifest 파일 정보를 표시합니다.
all_manifests와 manifests는 구조가 같습니다. 차이점은 all_manifests가 모든 유효한 스냅샷의 manifest 파일을 포함하는 반면, manifests는 현재 스냅샷의 manifest 파일만 포함한다는 것입니다.
SELECT * FROM iceberg_table$all_manifests;
결과 형식은 manifests 시스템 테이블과 같습니다.
metadata_log_entries
테이블의 메타데이터 로그를 표시합니다.
SELECT * FROM iceberg_table$metadata_log_entries;
결과:
+----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+------------------+------------------------+
| timestamp | file | latest_snapshot_id | latest_schema_id | latest_sequence_number |
+----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+------------------+------------------------+
| 2025-06-12 22:29:06.948000 | s3://.../iceberg_table/metadata/00000-e373aa16-15f1-4e69-ae7d-5ed64199cf9a.metadata.json | NULL | NULL | NULL |
| 2025-06-12 22:29:16.357000 | s3://.../iceberg_table/metadata/00001-bbc8e244-e41c-4958-92f4-63b8c3ee1196.metadata.json | 1851184769713369003 | 0 | 1 |
| 2025-06-12 22:29:39.922000 | s3://.../iceberg_table/metadata/00002-7dc00d6a-6269-4200-9d28-5f8c1c6b9f99.metadata.json | 4890031351138056789 | 0 | 2 |
+----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+------------------+------------------------+
partitions
테이블의 파티션을 표시합니다.
SELECT * FROM iceberg_table$partitions;
결과:
+-----------+---------+--------------+------------+-------------------------------+------------------------------+----------------------------+------------------------------+----------------------------+----------------------------+--------------------------+
| partition | spec_id | record_count | file_count | total_data_file_size_in_bytes | position_delete_record_count | position_delete_file_count | equality_delete_record_count | equality_delete_file_count | last_updated_at | last_updated_snapshot_id |
+-----------+---------+--------------+------------+-------------------------------+------------------------------+----------------------------+------------------------------+----------------------------+----------------------------+--------------------------+
| {"id":8} | 0 | 1 | 1 | 625 | 0 | 0 | 0 | 0 | 2025-06-12 22:29:16.357000 | 1851184769713369003 |
| {"id":6} | 0 | 1 | 1 | 625 | 0 | 0 | 0 | 0 | 2025-06-12 22:29:16.357000 | 1851184769713369003 |
| {"id":10} | 0 | 1 | 1 | 618 | 0 | 0 | 0 | 0 | 2025-06-12 22:29:16.357000 | 1851184769713369003 |
| {"id":4} | 0 | 1 | 1 | 618 | 0 | 0 | 0 | 0 | 2025-06-12 22:29:16.357000 | 1851184769713369003 |
| {"id":2} | 0 | 1 | 1 | 611 | 0 | 0 | 0 | 0 | 2025-06-12 22:29:16.357000 | 1851184769713369003 |
+-----------+---------+--------------+------------+-------------------------------+------------------------------+----------------------------+------------------------------+----------------------------+----------------------------+--------------------------+
참고:
- 파티션이 없는 테이블의 경우
partitions테이블에는partition및spec_id필드가 포함되지 않습니다. partitions테이블은 현재 스냅샷에서 데이터 파일이나 삭제 파일이 있는 파티션을 표시합니다. 다만 삭제 파일을 적용하지 않으므로, 파티션의 모든 데이터 행이 삭제 파일에 의해 삭제된 것으로 표시되어 있어도 일부 경우에는 해당 파티션이 계속 표시될 수 있습니다.
refs
테이블의 알려진 모든 스냅샷 참조(브랜치 및 태그)를 표시합니다.
SELECT * FROM iceberg_table$refs;
결과:
+------+--------+---------------------+-------------------------+-----------------------+------------------------+
| name | type | snapshot_id | max_reference_age_in_ms | min_snapshots_to_keep | max_snapshot_age_in_ms |
+------+--------+---------------------+-------------------------+-----------------------+------------------------+
| main | BRANCH | 4890031351138056789 | NULL | NULL | NULL |
+------+--------+---------------------+-------------------------+-----------------------+------------------------+
snapshots
테이블의 모든 스냅샷을 표시합니다.
SELECT * FROM iceberg_table$snapshots;
결과:
+----------------------------+---------------------+---------------------+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| committed_at | snapshot_id | parent_id | operation | manifest_list | summary |
+----------------------------+---------------------+---------------------+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 2025-06-12 22:29:16.357000 | 1851184769713369003 | NULL | append | s3://.../iceberg_table/metadata/snap-1851184769713369003-1-82059f57-821a-4983-b083-002cc2cde313.avro | {"spark.app.id":"application_1738810850199_0472", "added-data-files":"10", "added-records":"10", "added-files-size":"6200", "changed-partition-count":"10", "total-records":"10", "total-files-size":"6200", "total-data-files":"10", "total-delete-files":"0", "total-position-deletes":"0", "total-equality-deletes":"0"} |
| 2025-06-12 22:29:39.922000 | 4890031351138056789 | 1851184769713369003 | overwrite | s3://.../iceberg_table/metadata/snap-4890031351138056789-1-3194eb8b-5ea4-4cbe-95ba-073229458e7b.avro | {"spark.app.id":"application_1738810850199_0472", "deleted-data-files":"5", "deleted-records":"5", "removed-files-size":"3103", "changed-partition-count":"5", "total-records":"5", "total-files-size":"3097", "total-data-files":"5", "total-delete-files":"0", "total-position-deletes":"0", "total-equality-deletes":"0"} |
+----------------------------+---------------------+---------------------+-----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
쓰기 작업
INSERT INTO
INSERT 작업은 대상 테이블에 데이터를 추가합니다.
예:
INSERT INTO iceberg_tbl VALUES (val1, val2, val3, val4);
INSERT INTO iceberg.iceberg_db.iceberg_tbl SELECT col1, col2 FROM internal.db1.tbl1;
INSERT INTO iceberg_tbl(col1, col2) VALUES (val1, val2);
INSERT INTO iceberg_tbl(col1, col2, partition_col1, partition_col2) VALUES (1, 2, 'beijing', '2023-12-12');
버전 3.1.0부터 지정한 브랜치에 데이터 쓰기를 지원합니다.
INSERT INTO iceberg_tbl@branch(b1) values (val1, val2, val3, val4);
INSERT INTO iceberg_tbl@branch(b1) (col3, col4) values (val3, val4);
INSERT OVERWRITE
INSERT OVERWRITE 작업은 테이블의 기존 데이터를 새 데이터로 완전히 대체합니다.
INSERT OVERWRITE TABLE iceberg_tbl VALUES (val1, val2, val3, val4);
INSERT OVERWRITE TABLE iceberg.iceberg_db.iceberg_tbl(col1, col2) SELECT col1, col2 FROM internal.db1.tbl1;
버전 3.1.0부터 지정한 브랜치에 데이터 쓰기를 지원합니다.
INSERT OVERWRITE TABLE iceberg_tbl@branch(b1) values (val1, val2, val3, val4);
INSERT OVERWRITE TABLE iceberg_tbl@branch(b1) (col3, col4) values (val3, val4);
버전 4.1.0부터 정적 파티션(또는 혼합 파티션)에 데이터 쓰기를 지원합니다.
-- Full Static Partition
INSERT OVERWRITE TABLE iceberg_tbl PARTITION (dt='2025-01-25', region='bj')
SELECT id, name FROM source_table;
-- Hybrid Partition Mode: "dt" is static, "region" comes from SELECT dynamically
INSERT OVERWRITE TABLE iceberg_tbl PARTITION (dt='2025-01-25')
SELECT id, name, region FROM source_table;
CTAS
CTAS(Create Table As Select) 문으로 Iceberg 테이블을 생성하고 데이터를 쓸 수 있습니다.
CREATE TABLE iceberg_ctas AS SELECT * FROM other_table;
CTAS는 파일 형식, 파티션 및 기타 속성 지정을 지원합니다.
CREATE TABLE iceberg_ctas
PARTITION BY LIST (pt1, pt2) ()
AS SELECT col1, pt1, pt2 FROM part_ctas_src WHERE col1 > 0;
CREATE TABLE iceberg.iceberg_db.iceberg_ctas (col1, col2, pt1)
PARTITION BY LIST (pt1) ()
PROPERTIES (
'write-format'='parquet',
'compression-codec'='zstd'
)
AS SELECT col1, pt1 AS col2, pt2 AS pt1 FROM test_ctas.part_ctas_src WHERE col1 > 0;
INSERT INTO BRANCH
3.1.0부터 지원
INSERT INTO iceberg_table@branch(b1) SELECT * FROM other_table;
INSERT OVERWRITE TABLE iceberg_table@branch(b1) SELECT * FROM other_table;
DELETE
실험적 기능으로, 버전 4.1.0부터 지원됩니다.
DELETE 작업은 Iceberg 테이블에서 지정한 조건을 만족하는 데이터 행을 삭제합니다. 이 작업은 주로 다음 내부 메커니즘을 기반으로 합니다. V2 형식 테이블에서는 시스템이 Position Delete 파일을 기록하고, V3 형식 테이블에서는 Puffin 형식의 Deletion Vectors 파일을 기록합니다.
사전 조건:
- Iceberg 테이블의 형식 버전(
format-version)은 2 이상이어야 합니다. V1 형식 테이블은DELETE작업을 지원하지 않습니다.
구문:
DELETE FROM iceberg_tbl WHERE <condition>;
예제:
-- Delete a single row
DELETE FROM iceberg_tbl WHERE id = 1;
-- Delete using multiple conditions
DELETE FROM iceberg_tbl WHERE age > 30 AND name = 'Bob';
-- Delete using a subquery
DELETE FROM iceberg_tbl WHERE id IN (SELECT id FROM other_table WHERE status = 'inactive');
파티션 테이블에서도 사용법은 동일합니다.
DELETE FROM iceberg_partition_tbl WHERE id = 10;
UPDATE
실험적 기능으로, 버전 4.1.0부터 지원됩니다.
UPDATE 작업은 Iceberg 테이블에서 지정한 조건을 만족하는 데이터 행을 수정합니다. 내부적으로 먼저 삭제 추적 정보(V2에서는 Position Delete 파일, V3에서는 Puffin 형식의 Deletion Vectors 사용)를 기록하여 이전 데이터 행을 무효로 표시한 다음, 갱신된 새 데이터 파일을 추가합니다(V3 형식 옵션이 활성화된 경우 새로 삽입된 행의 추적 값인 _last_updated_sequence_number가 자동으로 증가함).
사전 조건:
- Iceberg 테이블의 형식 버전(
format-version)은 2 이상이어야 합니다. V1 형식 테이블은UPDATE작업을 지원하지 않습니다.
구문:
UPDATE iceberg_tbl SET <column1> = <value1> [, <column2> = <value2>, ...] WHERE <condition>;
예제:
-- Update a single column
UPDATE iceberg_tbl SET name = 'Alice_new' WHERE id = 1;
-- Update multiple columns
UPDATE iceberg_tbl SET name = 'Updated', age = 28 WHERE id = 2;
-- Update using expressions
UPDATE iceberg_tbl SET age = age * 2 + 1, name = concat(name, '-modified') WHERE id = 3;
-- Update using a subquery as condition
UPDATE iceberg_tbl SET name = 'UpdatedViaSubquery' WHERE id IN (SELECT id FROM other_table);
파티션 테이블에서도 사용법은 동일합니다.
UPDATE iceberg_partition_tbl SET name = 'Updated' WHERE id = 10;
MERGE INTO
실험적 기능으로, 버전 4.1.0부터 지원됩니다.
MERGE INTO 작업은 소스 데이터를 대상 Iceberg 테이블과 매칭한 뒤, 매칭 결과에 따라 삽입, 갱신 또는 삭제 작업을 수행합니다. 데이터 동기화 및 증분 갱신과 같은 시나리오에 적합합니다.
사전 조건:
- Iceberg 테이블의 형식 버전(
format-version)은 2 이상이어야 합니다. V1 형식 테이블은MERGE INTO작업을 지원하지 않습니다.
구문:
MERGE INTO target_table t
USING <source> s
ON <merge_condition>
[WHEN MATCHED [AND <condition>] THEN DELETE]
[WHEN MATCHED [AND <condition>] THEN UPDATE SET <column1> = <value1> [, ...]]
[WHEN NOT MATCHED [AND <condition>] THEN INSERT (<columns>) VALUES (<values>)]
여기서 <source>는 하위 쿼리 또는 다른 테이블일 수 있습니다.
예제:
-
전체 매칭 작업(갱신, 삭제, 삽입 포함):
MERGE INTO iceberg_tbl t
USING (
SELECT 1 AS id, 'Alice_new' AS name, 26 AS age, 'U' AS flag
UNION ALL
SELECT 2, 'Bob', 30, 'D'
UNION ALL
SELECT 4, 'Dora', 28, 'I'
) s
ON t.id = s.id
WHEN MATCHED AND s.flag = 'D' THEN DELETE
WHEN MATCHED THEN UPDATE SET
name = s.name,
age = s.age
WHEN NOT MATCHED THEN INSERT (id, name, age)
VALUES (s.id, s.name, s.age);위 예제에서는 다음과 같이 처리됩니다.
id = 2인 행은flag = 'D'이므로 삭제됩니다.id = 1인 행은 새로운name과age로 갱신됩니다.id = 4인 행은 대상 테이블에 없으므로 삽입됩니다.
-
매칭된 행의 갱신만 실행:
MERGE INTO iceberg_tbl t
USING (SELECT 1 AS id, 'Alice_matched' AS name, 26 AS age) s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET name = s.name, age = s.age; -
매칭되지 않은 행의 삽입만 실행:
MERGE INTO iceberg_tbl t
USING (SELECT 4 AS id, 'Dora' AS name, 40 AS age) s
ON t.id = s.id
WHEN NOT MATCHED THEN INSERT (id, name, age) VALUES (s.id, s.name, s.age); -
하위 쿼리를 데이터 소스로 사용:
MERGE INTO iceberg_tbl t
USING (SELECT id FROM other_table WHERE id = 2) s
ON t.id = s.id
WHEN MATCHED THEN UPDATE SET name = 'UpdatedViaSubquery'; -
파티션 테이블의
MERGE INTO작업:MERGE INTO iceberg_partition_tbl t
USING (
SELECT 1 AS id, 'Alice_new' AS name, 26 AS age, DATE '2024-01-01' AS dt, 'U' AS flag
UNION ALL
SELECT 2, 'Bob', 30, DATE '2024-01-02', 'D'
UNION ALL
SELECT 4, 'Dora', 28, DATE '2024-01-04', 'I'
) s
ON t.id = s.id
WHEN MATCHED AND s.flag = 'D' THEN DELETE
WHEN MATCHED THEN UPDATE SET
name = s.name,
age = s.age
WHEN NOT MATCHED THEN INSERT (id, name, age, dt)
VALUES (s.id, s.name, s.age, s.dt);
참고 사항:
- 위의 세 작업(
DELETE,UPDATE,MERGE INTO)은 모두 Iceberg 테이블의 형식 버전(format-version)이 2 이상이어야 합니다. V1 형식 테이블에서 실행하면must have format version 2 or higher for position deletes오류가 발생합니다. V3 형식 테이블에서 실행하면 시스템은 기존 Position Delete 데이터를 Puffin 형식의 Deletion Vectors로 대체하고, 내용 갱신이 포함된 경우 기록되는 레코드의 계보 수명 주기 속성(_last_updated_sequence_number)도 자동으로 조정합니다. - 이 작업들은 Parquet와 ORC 파일 형식을 모두 지원합니다.
- 동시 쓰기 시나리오에서 Iceberg는 낙관적 동시성 제어 메커니즘을 제공합니다. 쓰기 충돌이 발생하면 트랜잭션 충돌 예외가 발생할 수 있습니다.
UPDATE작업은 단독으로 실행하거나MERGE INTO내부에서 실행할 때 모두age = age * 2 + 1또는name = concat(name, '-modified')와 같은 표현식과 함수 사용을 지원합니다.- 이 작업들은 파티션 테이블과 비파티션 테이블에 모두 적용됩니다.
- 버전 4.1.4부터(모든 BE를 업그레이드해야 함)
MERGE INTO는 소스와 대상 테이블 사이의 매칭 관계를 검증합니다. 동일한 대상 행에 여러 소스 행이 매칭되면, 비결정적인 결과를 생성하는 대신multiple source rows matched the same target row오류로 문이 실패합니다. 일대다 매칭이 예상되는 경우 먼저 소스 측에서 중복을 제거하세요.
관련 매개변수
-
BE(Backend)
매개변수 이름 기본값 설명 iceberg_sink_max_file_size1GB 최대 데이터 파일 크기입니다. 기록된 데이터가 이 크기를 초과하면 현재 파일을 닫고 새 파일을 생성하여 쓰기를 계속합니다. table_sink_partition_write_max_partition_nums_per_writer128 BE 노드에서 각 인스턴스가 쓸 수 있는 최대 파티션 수입니다. table_sink_non_partition_write_scaling_data_processed_threshold25MB 비파티션 테이블에서 쓰기 확장을 시작하는 데이터 임계값입니다. 데이터가 table_sink_non_partition_write_scaling_data_processed_threshold만큼 추가될 때마다 새 쓰기 인스턴스를 사용합니다. 이 메커니즘은 데이터 양에 따라 쓰기 인스턴스 수를 조정하여 처리량을 높이면서, 데이터 양이 적을 때는 리소스를 절약하고 파일 수를 최소화합니다.table_sink_partition_write_min_data_processed_rebalance_threshold25MB 파티션 테이블에서 재분배를 시작하는 최소 데이터 양 임계값입니다. current accumulated data volume-data volume since last rebalancing>=table_sink_partition_write_min_data_processed_rebalance_threshold이면 재분배가 시작됩니다. 파일 크기 차이가 큰 경우 이 임계값을 낮추면 균형을 개선할 수 있지만, 재분배 비용이 늘어나 성능에 영향을 줄 수 있습니다.table_sink_partition_write_min_partition_data_processed_rebalance_threshold재분배를 시작하는 최소 파티션 데이터 양 임계값입니다. current partition data volume>=threshold*number of tasks already allocated to the partition이면 재분배가 시작됩니다. 파일 크기 차이가 큰 경우 이 임계값을 낮추면 균형을 개선할 수 있지만, 재분배 비용이 늘어나 성능에 영향을 줄 수 있습니다.
데이터베이스 및 테이블 관리
데이터베이스 생성 및 삭제
SWITCH 문으로 원하는 Catalog로 전환한 다음 CREATE DATABASE 명령을 실행할 수 있습니다.
SWITCH iceberg;
CREATE DATABASE [IF NOT EXISTS] iceberg_db;
전체 이름을 사용하여 데이터베이스를 생성하거나 데이터베이스 속성을 지정할 수도 있습니다. 예:
CREATE DATABASE [IF NOT EXISTS] iceberg.iceberg_db;
CREATE DATABASE [IF NOT EXISTS] iceberg.iceberg_db
PROPERTIES ('location'='hdfs://172.21.16.47:4007/path/to/db/');
데이터베이스 속성 지원 매트릭스(버전 4.1.4부터 확장):
Catalog 유형(iceberg.catalog.type) | 일반 데이터베이스 속성 | location 속성 |
|---|---|---|
hms | 지원 | 지원 |
glue | 지원(4.1.4부터) | 지원(4.1.4부터) |
jdbc | 지원(4.1.4부터) | 미지원 |
hadoop / rest / dlf / s3tables | 미지원 | 미지원 |
속성이 지원되지 않을 때 발생하는 오류 메시지:
- 일반 속성:
Not supported: create database with properties for iceberg catalog type: <type> location속성:Not supported: database property 'location' for iceberg catalog type: <type> because it does not determine the default table location
REST 프로토콜에서는 서버가 Namespace 속성을 무시할 수 있으므로 REST Catalog는 데이터베이스 속성을 지원하지 않습니다.
SHOW CREATE DATABASE 명령으로 데이터베이스의 위치 정보를 확인할 수 있습니다.
mysql> SHOW CREATE DATABASE iceberg_db;
+-------------+-------------------------------------------------------------------------------------------------+
| Database | Create Database |
+-------------+-------------------------------------------------------------------------------------------------+
| iceberg_db | CREATE DATABASE iceberg_db LOCATION 'hdfs://172.21.16.47:4007/usr/hive/warehouse/iceberg_db.db' |
+-------------+-------------------------------------------------------------------------------------------------+
데이터베이스를 삭제하려면 다음을 실행합니다.
DROP DATABASE [IF EXISTS] iceberg.iceberg_db;
Iceberg 데이터베이스를 삭제하려면 먼저 해당 데이터베이스의 모든 테이블을 삭제해야 합니다. 그렇지 않으면 오류가 발생합니다.
테이블 생성 및 삭제
-
테이블 생성
Doris는 Iceberg에서 파티션 테이블과 비파티션 테이블 생성을 모두 지원합니다.
예:
-- Create unpartitioned iceberg table
CREATE TABLE unpartitioned_table (
`col1` BOOLEAN COMMENT 'col1',
`col2` INT COMMENT 'col2',
`col3` BIGINT COMMENT 'col3',
`col4` FLOAT COMMENT 'col4',
`col5` DOUBLE COMMENT 'col5',
`col6` DECIMAL(9,4) COMMENT 'col6',
`col7` STRING COMMENT 'col7',
`col8` DATE COMMENT 'col8',
`col9` DATETIME COMMENT 'col9'
)
PROPERTIES (
'write-format'='parquet'
);
-- Create partitioned iceberg table
-- The partition columns must be in table's column definition list
CREATE TABLE partition_table (
`ts` DATETIME COMMENT 'ts',
`col1` BOOLEAN COMMENT 'col1',
`col2` INT COMMENT 'col2',
`col3` BIGINT COMMENT 'col3',
`col4` FLOAT COMMENT 'col4',
`col5` DOUBLE COMMENT 'col5',
`col6` DECIMAL(9,4) COMMENT 'col6',
`col7` STRING COMMENT 'col7',
`col8` DATE COMMENT 'col8',
`col9` DATETIME COMMENT 'col9',
`pt1` STRING COMMENT 'pt1',
`pt2` STRING COMMENT 'pt2'
)
PARTITION BY LIST (day(ts), pt1, pt2) ()
PROPERTIES (
'write-format'='orc',
'compression-codec'='zlib'
);버전 4.1.0부터 Doris는 Iceberg 테이블 생성 시 정렬 컬럼 지정을 지원합니다. 데이터를 쓸 때 지정한 정렬 컬럼을 기준으로 정렬하여 쿼리 성능을 높입니다.
CREATE TABLE ordered_table (
`id` int NULL,
`name` text NULL,
`score` double NULL,
`create_time` datetimev2(6) NULL
)
ORDER BY (`id` ASC NULLS FIRST, `score` DESC NULLS LAST)
PROPERTIES (
"write-format" = "parquet",
"write.parquet.compression-codec" = "zstd"
);- 정렬 컬럼을 지정하지 않으면 쓰기 시 정렬하지 않습니다.
- 기본 정렬 순서는 ASC NULLS FIRST입니다.
생성 후
SHOW CREATE TABLE명령으로 Iceberg 테이블 생성문을 확인할 수 있습니다. 파티션 함수에 대한 자세한 내용은 파티션 섹션을 참조하세요. -
테이블 삭제
DROP TABLE문으로 Iceberg 테이블을 삭제할 수 있습니다. 테이블을 삭제하면 파티션 데이터를 포함한 테이블 데이터도 제거됩니다.예:
DROP TABLE [IF EXISTS] iceberg_tbl; -
컬럼 유형 매핑
컬럼 유형 매핑 섹션을 참조하세요.
-
파티션
Iceberg의 파티션 유형은 Doris의 List 파티션에 대응합니다. 따라서 Doris에서 Iceberg 파티션 테이블을 생성할 때는 List 파티션 구문을 사용하되, 각 파티션을 명시적으로 나열할 필요는 없습니다. Doris는 데이터 삽입 시 데이터 값을 기반으로 해당 Iceberg 파티션을 자동 생성합니다.
-
단일 컬럼 또는 다중 컬럼 파티션 테이블 생성을 지원합니다.
-
Iceberg의 암시적 파티션과 파티션 진화를 위한 파티션 변환 함수를 지원합니다. 구체적인 Iceberg 파티션 변환 함수는 Iceberg 파티션 변환을 참조하세요.
-
year(ts)또는years(ts) -
month(ts)또는months(ts) -
day(ts)또는days(ts)또는date(ts) -
hour(ts)또는hours(ts)또는date_hour(ts) -
bucket(N, col) -
truncate(L, col)
-
-
-
파일 형식
-
Parquet(기본값)
Doris에서 생성한 Iceberg 테이블의 Datetime은
timestamp_ntz유형에 대응합니다.3.1.0 이후 버전에서는 Datetime 유형을 Parquet 파일에 쓸 때 물리적 유형으로 INT96 대신 INT64를 사용합니다.
다른 시스템에서 생성한 Iceberg 테이블에서는
timestamp와timestamp_ntz유형이 모두 Doris의 Datetime 유형으로 매핑됩니다. 다만 쓰기 시에는 실제 유형을 기준으로 시간대 처리 여부를 결정합니다. -
ORC
-
-
압축 형식
-
Parquet: snappy, zstd(기본값), plain(압축 없음).
-
ORC: snappy, zlib(기본값), zstd, plain(압축 없음).
-
-
스토리지 매체
-
HDFS
-
객체 스토리지
-
스키마 변경
3.1.0부터 Doris는 Iceberg 테이블의 스키마 변경을 지원하며, ALTER TABLE 문으로 수정할 수 있습니다.
지원되는 스키마 변경 작업은 다음과 같습니다.
-
컬럼 이름 변경
RENAME COLUMN절로 컬럼 이름을 변경합니다. 버전 4.1.4부터 중첩 유형 내부의 컬럼 이름 변경을 지원하며,TO키워드는 선택 사항입니다.ALTER TABLE iceberg_table RENAME COLUMN old_col_name TO new_col_name;
-- Supported since 4.1.4: TO can be omitted
ALTER TABLE iceberg_table RENAME COLUMN old_col_name new_col_name;
-- Supported since 4.1.4: rename a nested field
ALTER TABLE iceberg_table RENAME COLUMN s.old_field TO new_field; -
단일 컬럼 추가
ADD COLUMN으로 새 컬럼을 추가합니다. 버전 4.1.4부터 점으로 구분된 경로(예:s.new_field)를 통해 중첩 유형(STRUCT)에 새 컬럼을 추가할 수 있습니다. 새로 추가하는 중첩 필드는 NULL을 허용해야 합니다.새 컬럼을 추가할 때 NULL 허용 속성, 기본값, 주석 및 컬럼 위치를 지정할 수 있습니다.
ALTER TABLE iceberg_table ADD COLUMN col_name col_type [NULL|NOT NULL, [DEFAULT default_value, [COMMENT 'comment', [FIRST|AFTER col_name]]]];예:
ALTER TABLE iceberg_table ADD COLUMN new_col STRING NOT NULL DEFAULT 'default_value' COMMENT 'This is a new col' AFTER old_col; -
여러 컬럼 추가
ADD COLUMN으로 여러 컬럼을 추가할 수도 있습니다. 새 컬럼은 테이블의 끝에 추가됩니다. 여러 컬럼을 추가할 때는 컬럼 위치 지정을 지원하지 않습니다. 중첩 유형에 새 컬럼을 추가하는 것은 지원하지 않습니다.각 컬럼의 구문은 단일 컬럼을 추가할 때와 같습니다.
ALTER TABLE iceberg_table ADD COLUMN (col_name1 col_type1 [NULL|NOT NULL, [DEFAULT default_value, [COMMENT 'comment']]], col_name2 col_type2 [NULL|NOT NULL, [DEFAULT default_value, [COMMENT 'comment']]] ...); -
컬럼 삭제
DROP COLUMN으로 컬럼을 삭제합니다. 버전 4.1.4부터 점으로 구분된 경로를 통해 중첩 유형 내부의 컬럼을 삭제할 수 있습니다.ALTER TABLE iceberg_table DROP COLUMN col_name;
-- Supported since 4.1.4: drop a nested field
ALTER TABLE iceberg_table DROP COLUMN s.field_name; -
컬럼 수정
MODIFY COLUMN문으로 유형, NULL 허용 여부, 기본값, 주석, 컬럼 위치 등 컬럼 속성을 수정합니다.버전 4.0.4부터 Doris는 안전한 유형 승격과 struct 필드 추가를 포함하여 복합 유형(STRUCT, ARRAY, MAP) 수정을 지원합니다.
중첩 유형에서 지원하는 안전한 유형 승격:
- INT -> BIGINT, LARGEINT
- TINYINT -> SMALLINT, INT, BIGINT, LARGEINT
- SMALLINT -> INT, BIGINT, LARGEINT
- BIGINT -> LARGEINT
- FLOAT -> DOUBLE
- VARCHAR(n) -> VARCHAR(m), 단 m > n
복합 유형의 제약 조건:
- 새 중첩 필드는 모두 NULL을 허용해야 합니다.
- 선택 필드를 필수 필드로 변경할 수 없습니다.
- 복합 유형의 기본값은 NULL만 지원합니다.
참고: 컬럼 속성을 수정할 때는 변경하지 않는 속성도 모두 원래 값으로 명시해야 합니다.
ALTER TABLE iceberg_table MODIFY COLUMN col_name col_type [NULL|NOT NULL, [DEFAULT default_value, [COMMENT 'comment', [FIRST|AFTER col_name]]]];예:
CREATE TABLE iceberg_table (
id INT,
name STRING
);
-- Modify the id column type to BIGINT, set as NOT NULL, default value to 0, and add comment
ALTER TABLE iceberg_table MODIFY COLUMN id BIGINT NOT NULL DEFAULT 0 COMMENT 'This is a modified id column';복합 유형 수정 예제:
-- Create Iceberg table with complex types
CREATE TABLE iceberg_tbl (
id BIGINT,
user_info STRUCT<name:STRING, scores:ARRAY<INT>, age:INT>,
dt STRING
);
-- Append a new field (email) to the STRUCT column
ALTER TABLE iceberg_tbl MODIFY COLUMN user_info STRUCT<name:STRING, scores:ARRAY<INT>, age:INT, email:STRING>;
-- Promote the nested ARRAY element type from INT to BIGINT
ALTER TABLE iceberg_tbl MODIFY COLUMN user_info STRUCT<name:STRING, scores:ARRAY<BIGINT>, age:INT, email:STRING>; -
컬럼 순서 변경
ORDER BY에 새 컬럼 순서를 지정하여 컬럼 순서를 변경합니다.ALTER TABLE iceberg_table ORDER BY (col_name1, col_name2, ...);
중첩 컬럼 스키마 변경(4.1.4+)
버전 4.1.4부터 ADD COLUMN, DROP COLUMN, MODIFY COLUMN, RENAME COLUMN은 모두 점으로 구분된 경로(예: a.b.c)를 받아 중첩 필드를 직접 조작할 수 있습니다. 이 기능은 Iceberg 테이블에만 적용됩니다. 다른 테이블 유형에서 사용하면 Nested column path is only supported for Iceberg tables: ... 오류가 발생합니다.
일반적인 제한 사항 및 오류:
| 오류 메시지 | 설명 |
|---|---|
New nested field '<path>' must be nullable | 새로 추가하는 중첩 필드는 NULL을 허용해야 합니다. |
Rollup is not supported for Iceberg column operations | Rollup 절은 지원하지 않습니다. |
PROPERTIES are not supported for Iceberg column operations | PROPERTIES 절은 지원하지 않습니다. |
KEY is not supported for Iceberg ADD/MODIFY COLUMN | KEY 키워드는 지원하지 않습니다. |
Generated columns are not supported for Iceberg ADD/MODIFY COLUMN | 생성 컬럼은 지원하지 않습니다. |
Modifying default values is not supported for Iceberg columns | 기존 컬럼의 기본값 수정은 지원하지 않습니다. |
ON UPDATE is not supported for Iceberg ADD COLUMN | ON UPDATE 절은 지원하지 않습니다. |
Modify column type from complex to primitive is not supported | 복합 유형을 기본 유형으로 변경하는 것은 지원하지 않습니다. |
Cannot change MAP key type from ... / Cannot <op> MAP key nested column | MAP 키 유형 변경이나 MAP 키에 대한 중첩 컬럼 작업은 지원하지 않습니다. |
Iceberg does not support comments on collection element or value fields | 컬렉션 요소 또는 MAP 값 필드에 대한 주석은 지원하지 않습니다. |
Multiple Iceberg ALTER clauses are not supported when a statement ... | 중첩 컬럼이 포함된 경우 문에는 ALTER 절을 하나만 포함할 수 있습니다. |
테이블 속성 수정
버전 4.1.4부터 지원됩니다.
ALTER TABLE ... SET (...)으로 Iceberg 테이블의 네이티브 속성을 수정할 수 있으며, 하나의 문에서 여러 속성을 설정할 수 있습니다.
ALTER TABLE iceberg_ctl.iceberg_db.iceberg_tbl SET (
'write.target-file-size-bytes' = '268435456',
'commit.manifest.min-count-to-merge' = '50'
);
참고 사항:
- 모든 속성은 하나의 Iceberg
UpdateProperties트랜잭션으로 원자적으로 커밋됩니다. 실패하면 어떤 속성도 적용되지 않으며 FE 메타데이터 새로 고침도 실행되지 않습니다. - Doris 자체의
auto_analyze_policy속성은 커넥터 네이티브 속성과 같은 문에서 함께 설정할 수 없습니다. 함께 설정하면auto_analyze_policy cannot be set with external table properties오류가 발생합니다. 단독으로 설정할 때 사용할 수 있는 값은 기존과 같이enable/disable/base_on_catalog입니다. - Catalog가 메타데이터 쓰기를 구현하지 않은 경우
Update table properties operation is not supported for catalog: <name>오류가 발생합니다.
파티션 진화
버전 4.0.2부터 Doris는 ALTER 문을 통한 Iceberg 테이블의 파티션 진화를 지원합니다.
지원되는 파티션 변환은 다음과 같습니다.
| 변환 | 구문 | 예시 |
|---|---|---|
| bucket | bucket(N, column) | bucket(16, id) |
| truncate | truncate(N, column) | truncate(10, name) |
| year | year(column) | year(ts) |
| month | month(column) | month(ts) |
| day | day(column) | day(ts) |
| hour | hour(column) | hour(ts) |
| identity | column | category |
지원되는 작업은 다음과 같습니다.
-
파티션 키 추가
-- use optional AS keyword to specify a custom name for the partition field
ALTER TABLE table_name ADD PARTITION KEY partition_transform [AS key_name];
-- example
ALTER TABLE prod.db.sample ADD PARTITION KEY bucket(16, id);
ALTER TABLE prod.db.sample ADD PARTITION KEY truncate(4, data);
ALTER TABLE prod.db.sample ADD PARTITION KEY year(ts);
-- use optional AS keyword to specify a custom name for the partition field
ALTER TABLE prod.db.sample ADD PARTITION KEY bucket(16, id) AS shard; -
파티션 키 삭제
ALTER TABLE table_name DROP PARTITION KEY partition_transform|key_name;
-- example
ALTER TABLE prod.db.sample DROP PARTITION KEY catalog;
ALTER TABLE prod.db.sample DROP PARTITION KEY bucket(16, id);
ALTER TABLE prod.db.sample DROP PARTITION KEY truncate(4, data);
ALTER TABLE prod.db.sample DROP PARTITION KEY year(ts);
ALTER TABLE prod.db.sample DROP PARTITION KEY shard; -
파티션 키 교체
-- use optional AS keyword to specify a custom name for the partition field
ALTER TABLE table_name REPLACE PARTITION KEY key_name WITH partition_transform [AS key_name];
-- example
ALTER TABLE prod.db.sample REPLACE PARTITION KEY ts_day WITH day(ts);
-- use optional AS keyword to specify a custom name for the new partition field
ALTER TABLE prod.db.sample REPLACE PARTITION KEY ts_day WITH day(ts) AS day_of_ts;
브랜치 및 태그 관리
3.1.0부터 지원
-
브랜치 생성
구문:
ALTER TABLE [catalog.][database.]table_name
CREATE [OR REPLACE] BRANCH [IF NOT EXISTS] <branch_name>
[AS OF VERSION <snapshot_id>]
[RETAIN <num> { DAYS | HOURS | MINUTES }]
[WITH SNAPSHOT RETENTION { snapshotKeep | timeKeep }]
snapshotKeep:
<num> SNAPSHOTS [<num> { DAYS | HOURS | MINUTES }]
timeKeep:
<num> { DAYS | HOURS | MINUTES }예제:
-- Create branch "b1".
ALTER TABLE tbl CREATE BRANCH b1;
ALTER TABLE tb1 CREATE BRANCH IF NOT EXISTS b1;
-- Create or replace branch "b1".
ALTER TABLE tb1 CREATE OR REPLACE BRANCH b1;
-- Create or replace branch "b1" based on snapshot "123456".
ALTER TABLE tb1 CREATE OR REPLACE BRANCH b1 AS OF VERSION 123456;
-- Create or replace branch "b1" based on snapshot "123456", branch retained for 1 day.
ALTER TABLE tb1 CREATE OR REPLACE BRANCH b1 AS OF VERSION 123456 RETAIN 1 DAYS;
-- Create branch "b1" based on snapshot "123456", branch retained for 30 days. Keep the latest 3 snapshots in the branch.
ALTER TABLE tb1 CREATE BRANCH b1 AS OF VERSION 123456 RETAIN 30 DAYS WITH SNAPSHOT RETENTION 3 SNAPSHOTS;
-- Create branch "b1" based on snapshot "123456", branch retained for 30 days. Snapshots in the branch are retained for at most 2 days.
ALTER TABLE tb1 CREATE BRANCH b1 AS OF VERSION 123456 RETAIN 30 DAYS WITH SNAPSHOT RETENTION 2 DAYS;
-- Create branch "b1" based on snapshot "123456", branch retained for 30 days. Keep the latest 3 snapshots in the branch, and snapshots in the branch are retained for at most 2 days.
ALTER TABLE tb1 CREATE BRANCH b1 AS OF VERSION 123456 RETAIN 30 DAYS WITH SNAPSHOT RETENTION 3 SNAPSHOTS 2 DAYS; -
브랜치 삭제
구문:
ALTER TABLE [catalog.][database.]table_name
DROP BRANCH [IF EXISTS] <branch_name>;예:
ALTER TABLE tbl DROP BRANCH b1; -
태그 생성
구문:
ALTER TABLE [catalog.][database.]table_name
CREATE [OR REPLACE] TAG [IF NOT EXISTS] <tag_name>
[AS OF VERSION <snapshot_id>]
[RETAIN <num> { DAYS | HOURS | MINUTES }]예제:
-- Create tag "t1".
ALTER TABLE tbl CREATE TAG t1;
ALTER TABLE tb1 CREATE TAG IF NOT EXISTS t1;
-- Create or replace tag "t1".
ALTER TABLE tb1 CREATE OR REPLACE TAG t1;
-- Create or replace tag "t1" based on snapshot "123456".
ALTER TABLE tb1 CREATE OR REPLACE TAG b1 AS OF VERSION 123456;
-- Create or replace tag "b1" based on snapshot "123456", tag retained for 1 day.
ALTER TABLE tb1 CREATE OR REPLACE TAG b1 AS OF VERSION 123456 RETAIN 1 DAYS; -
태그 삭제
구문:
ALTER TABLE [catalog.][database.]table_name
DROP TAG [IF EXISTS] <tag_name>;예:
ALTER TABLE tbl DROP TAG t1;
Iceberg 테이블 작업
이 기능은 버전 4.0.2부터 지원됩니다. 각 작업의 구체적인 버전 요구 사항을 확인하세요.
실험적 기능입니다.
Doris는 ALTER TABLE EXECUTE 구문으로 특정 Iceberg 테이블 작업을 실행할 수 있습니다. 이 구문은 테이블 최적화와 스냅샷 관리 등 다양한 작업을 실행하는 통합 인터페이스를 제공합니다.
ALTER TABLE [catalog.][database.]table_name
EXECUTE <action_name> ("key1" = "value1", "key2" = "value2", ...)
[WHERE <condition>]
action_name: 실행할 작업의 이름("key1" = "value1", ...): 키-값 쌍으로 제공하는 작업 관련 매개변수입니다. 매개변수 이름은 큰따옴표로 묶어야 합니다.[WHERE <condition>]: 작업할 파티션 또는 데이터 범위를 지정하는 선택적 WHERE 조건입니다(일부 작업에서만 지원).
cherrypick_snapshot
cherrypick_snapshot 작업은 지정한 스냅샷의 변경 사항을 현재 테이블 상태에 병합하고, 원본 스냅샷을 수정하거나 삭제하지 않은 채 새 스냅샷을 생성합니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE cherrypick_snapshot ("snapshot_id" = "<snapshot_id>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
snapshot_id | Long | 예 | 병합할 스냅샷 ID |
반환값:
cherrypick_snapshot 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
source_snapshot_id | BIGINT | 병합된 스냅샷 ID |
current_snapshot_id | BIGINT | 병합 작업 후 새로 생성되어 현재 스냅샷으로 설정된 스냅샷 ID |
예:
-- Merge changes from snapshot 123456789 into the current table state
ALTER TABLE iceberg_db.iceberg_table
EXECUTE cherrypick_snapshot ("snapshot_id" = "123456789");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
- 지정한 스냅샷이 없으면 작업이 실패합니다.
- 병합 작업은 새 스냅샷을 생성하며 원본 스냅샷은 삭제하지 않습니다.
expire_snapshots
expire_snapshots 작업은 Iceberg 테이블에서 오래된 스냅샷을 제거하여 스토리지 공간을 확보하고 메타데이터 성능을 개선합니다. 이 작업은 Apache Iceberg Spark 프로시저 사양을 따릅니다.
지원 버전: 4.1.0+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE expire_snapshots ("key1" = "value1", "key2" = "value2", ...)
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
older_than | String | 아니요 | 스냅샷 만료 기준 시각입니다. 이 시각보다 오래된 스냅샷을 제거합니다. ISO 날짜/시간 형식(예: 2024-01-01T00:00:00) 또는 밀리초 타임스탬프를 지원합니다. |
retain_last | Integer | 아니요 | 보존할 조상 스냅샷 수입니다. 단독으로 지정하면 older_than을 현재 시각으로 자동 설정합니다. |
snapshot_ids | String | 아니요 | 만료할 특정 스냅샷 ID를 쉼표로 구분한 목록입니다. |
max_concurrent_deletes | Integer | 아니요 | 삭제 작업에 사용하는 스레드 풀의 크기입니다. |
clean_expired_metadata | Boolean | 아니요 | true로 설정하면 사용하지 않는 파티션 사양과 스키마를 정리합니다. |
반환값:
expire_snapshots 작업을 실행하면 다음 6개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
deleted_data_files_count | BIGINT | 삭제된 데이터 파일 수 |
deleted_position_delete_files_count | BIGINT | 삭제된 Position Delete 파일 수 |
deleted_equality_delete_files_count | BIGINT | 삭제된 Equality Delete 파일 수 |
deleted_manifest_files_count | BIGINT | 삭제된 manifest 파일 수 |
deleted_manifest_lists_count | BIGINT | 삭제된 manifest 목록 파일 수 |
deleted_statistics_files_count | BIGINT | 삭제된 통계 파일 수 |
예:
-- Expire snapshots, keeping only the last 2
ALTER TABLE iceberg_db.iceberg_table
EXECUTE expire_snapshots ("retain_last" = "2");
-- Expire snapshots older than a specific timestamp
ALTER TABLE iceberg_db.iceberg_table
EXECUTE expire_snapshots ("older_than" = "2024-01-01T00:00:00");
-- Expire specific snapshots by ID
ALTER TABLE iceberg_db.iceberg_table
EXECUTE expire_snapshots ("snapshot_ids" = "123456789,987654321");
-- Combine parameters: expire snapshots older than 2024-06-01 but keep at least the last 5
ALTER TABLE iceberg_db.iceberg_table
EXECUTE expire_snapshots ("older_than" = "2024-06-01T00:00:00", "retain_last" = "5");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
older_than과retain_last를 모두 지정하면 두 조건이 모두 적용됩니다. 즉,older_than보다 오래되었고 최근retain_last개 스냅샷에 포함되지 않는 스냅샷만 삭제됩니다.snapshot_ids를 단독으로 사용하여 특정 스냅샷을 삭제할 수 있습니다.- 이 작업은 스냅샷과 관련 데이터 파일을 영구적으로 삭제합니다. 주의해서 사용하세요.
- 실행 전에
$snapshots시스템 테이블을 쿼리하여 테이블의 스냅샷 정보를 확인하는 것이 좋습니다.
fast_forward
fast_forward 작업은 한 브랜치의 현재 스냅샷을 다른 브랜치의 최신 스냅샷으로 빠르게 이동시킵니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE fast_forward ("branch" = "<branch_name>", "to" = "<target_branch>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
branch | String | 예 | 이동시킬 브랜치 이름 |
to | String | 예 | 대상 브랜치 이름입니다. branch가 이 브랜치의 최신 스냅샷으로 이동합니다. |
반환값:
fast_forward 작업을 실행하면 다음 3개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
branch_updated | STRING | 이동한 브랜치의 이름 |
previous_ref | BIGINT | 이동 전 브랜치가 가리키던 스냅샷 ID(NULL일 수 있음) |
updated_ref | BIGINT | 이동 후 브랜치가 가리키는 스냅샷 ID |
예:
-- Advance the feature branch to the latest snapshot of the main branch
ALTER TABLE iceberg_db.iceberg_table
EXECUTE fast_forward ("branch" = "feature", "to" = "main");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
- 지정한 브랜치가 없으면 작업이 실패합니다.
- 브랜치만 이동할 수 있으며 태그는 이동할 수 없습니다.
publish_changes
publish_changes 작업은 Write-Audit-Publish(WAP) 패턴의 "게시" 단계입니다. 이 과정은 특정 wap.id 속성이 있는 스냅샷을 찾아 현재 테이블 상태에 추가합니다. 이를 통해 사용자는 검증 후 "준비된" 데이터를 원자적으로 공개할 수 있습니다.
지원 버전: 4.1.0+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE publish_changes ("wap_id" = "<wap-id>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
wap_id | String | 예 | 게시할 스냅샷의 wap.id |
반환값:
publish_changes 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
previous_snapshot_id | BIGINT | 게시 전 스냅샷 ID |
current_snapshot_id | BIGINT | 게시 후 새 스냅샷 ID |
예:
ALTER TABLE iceberg_db.iceberg_table
EXECUTE publish_changes ("wap_id" = "branch-123")
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
- 지정한
wap.id가 없으면 작업이 실패합니다.
rewrite_data_files
rewrite_data_files 작업은 Iceberg 테이블의 데이터 파일을 다시 작성하여 작은 파일을 병합하고, 쿼리 성능과 스토리지 효율을 최적화합니다. 동기식 작업입니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE rewrite_data_files ("key1" = "value1", "key2" = "value2", ...) [WHERE <condition>]
매개변수:
| 매개변수 | 유형 | 기본값 | 설명 |
|---|---|---|---|
target-file-size-bytes | Long | 536870912 (512MB) | 바이트 단위의 목표 파일 크기입니다. 출력 파일의 목표 크기입니다. |
min-file-size-bytes | Long | target-file-size-bytes * 0.75 | 바이트 단위의 최소 파일 크기입니다. 이보다 작은 파일은 다시 작성됩니다. 지정하지 않으면 목표 파일 크기의 75%가 기본값입니다. |
max-file-size-bytes | Long | target-file-size-bytes * 1.8 | 바이트 단위의 최대 파일 크기입니다. 이보다 큰 파일은 분할됩니다. 지정하지 않으면 목표 파일 크기의 180%가 기본값입니다. |
min-input-files | Integer | 5 | 다시 작성을 시작하는 최소 입력 파일 수입니다. 다시 작성할 파일 수가 이 임계값에 도달해야 실행됩니다. |
rewrite-all | Boolean | false | 파일 크기와 관계없이 모든 파일을 다시 작성할지 여부입니다. |
max-file-group-size-bytes | Long | 107374182400 (100GB) | 바이트 단위의 단일 파일 그룹 최대 크기입니다. 단일 다시 작성 작업이 처리할 데이터 양을 제한하는 데 사용합니다. |
delete-file-threshold | Integer | Integer.MAX_VALUE | 다시 작성을 시작하는 데 필요한 최소 삭제 파일 수입니다. |
delete-ratio-threshold | Double | 0.3 | 다시 작성을 시작하는 데 필요한 최소 삭제 레코드 비율입니다(삭제된 레코드 / 전체 레코드). 범위: 0.0 - 1.0 |
output-spec-id | Long | 2 | 출력 파일의 파티션 사양 ID입니다. |
반환값:
rewrite_data_files 작업을 실행하면 다음 4개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
rewritten_data_files_count | INT | 다시 작성된 데이터 파일 수 |
added_data_files_count | INT | 새로 추가된 데이터 파일 수 |
rewritten_bytes_count | INT | 다시 작성된 바이트 수 |
removed_delete_files_count | BIGINT | 제거된 삭제 파일 수 |
예제:
-- Rewrite data files with default parameters
ALTER TABLE iceberg_db.iceberg_table EXECUTE rewrite_data_files();
-- Specify target file size and minimum input files
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rewrite_data_files (
"target-file-size-bytes" = "134217728",
"min-input-files" = "10"
);
-- Rewrite data in specific partitions using WHERE condition
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rewrite_data_files (
"target-file-size-bytes" = "268435456"
)
WHERE date_col = '2024-01-01';
-- Rewrite all files
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rewrite_data_files (
"rewrite-all" = "true",
"target-file-size-bytes" = "536870912"
);
참고 사항:
rewrite_data_files작업은 데이터 파일을 읽고 다시 작성하므로 추가 I/O 및 컴퓨팅 오버헤드가 발생합니다. 클러스터 리소스를 적절히 할당하세요.- 실행 전에 데이터 파일 분포 확인 섹션의 SQL로 다시 작성이 필요한지 평가할 수 있습니다.
- WHERE 조건으로 다시 작성할 파티션이나 데이터 범위를 제한할 수 있습니다. 이 조건은 WHERE 조건과 일치하는 데이터가 없는 파일을 제외하여 다시 작성할 파일 수와 데이터 양을 줄입니다.
- 실행 전에 다시 작성할 파일 선택 로직 섹션의 SQL로 어떤 파일이 다시 작성될지 계산할 수 있습니다.
rewrite_manifests
rewrite_manifests 작업은 manifest 파일을 다시 작성하여 Iceberg 테이블 메타데이터를 최적화하고, 쿼리 성능을 높이며 메타데이터 오버헤드를 줄입니다.
작은 manifest 파일이 많으면 쿼리 계획 수립 성능에 영향을 줄 수 있으므로, 이 작업으로 대형 Iceberg 테이블의 manifest 파일 최적화 문제를 해결할 수 있습니다.
지원 버전: 4.1.0+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE rewrite_manifests();
매개변수:
매개변수 없음
반환값:
rewrite_manifests 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
rewritten_manifests_count | BIGINT | 다시 작성된 파일 수 |
total_data_manifests_count | BIGINT | 다시 작성된 데이터 manifest 파일 수 |
예:
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rewrite_manifests();
rollback_to_snapshot
rollback_to_snapshot 작업은 Iceberg 테이블을 지정한 스냅샷으로 롤백합니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE rollback_to_snapshot ("snapshot_id" = "<snapshot_id>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
snapshot_id | Long | 예 | 롤백할 스냅샷 ID |
반환값:
rollback_to_snapshot 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
previous_snapshot_id | BIGINT | 롤백 전 현재 스냅샷의 ID |
current_snapshot_id | BIGINT | 롤백 후 현재 스냅샷으로 설정된 스냅샷 ID |
예:
-- Roll back to snapshot 987654321
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rollback_to_snapshot ("snapshot_id" = "987654321");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
- 지정한 스냅샷이 없으면 작업이 실패합니다.
- 현재 스냅샷이 이미 대상 스냅샷이면 새 스냅샷을 생성하지 않고 즉시 반환합니다.
rollback_to_timestamp
rollback_to_timestamp 작업은 Iceberg 테이블을 지정한 시점의 스냅샷으로 롤백합니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE rollback_to_timestamp ("timestamp" = "<timestamp>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
timestamp | String | 예 | 롤백할 시점입니다. 두 가지 형식을 지원합니다. 1. ISO 날짜/시간 형식: yyyy-MM-dd HH:mm:ss.SSS(예: 2024-01-01 10:30:00.000)2. 밀리초 타임스탬프(예: 1704067200000) |
반환값:
rollback_to_timestamp 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
previous_snapshot_id | BIGINT | 롤백 전 현재 스냅샷의 ID |
current_snapshot_id | BIGINT | 지정한 시점의 스냅샷 ID로, 현재 스냅샷으로 설정됨 |
예제:
-- Roll back to specified point in time (ISO format)
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rollback_to_timestamp ("timestamp" = "2024-01-01 10:30:00.000");
-- Roll back to specified point in time (timestamp format)
ALTER TABLE iceberg_db.iceberg_table
EXECUTE rollback_to_timestamp ("timestamp" = "1704067200000");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
timestamp매개변수는 ISO 날짜/시간 형식(yyyy-MM-dd HH:mm:ss.SSS) 또는 밀리초 타임스탬프 형식을 지원합니다.- 지정한 시점에 해당하는 스냅샷이 없으면 작업이 실패합니다.
set_current_snapshot
set_current_snapshot 작업은 Iceberg 테이블의 현재 스냅샷을 지정한 스냅샷 ID 또는 참조(브랜치나 태그)로 설정합니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE set_current_snapshot ("snapshot_id" = "<snapshot_id>" | "ref" = "<ref_name>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
snapshot_id | Long | 둘 중 하나 | 현재 스냅샷으로 설정할 스냅샷 ID |
ref | String | 둘 중 하나 | 현재 스냅샷으로 설정할 참조 이름(브랜치 또는 태그) |
반환값:
set_current_snapshot 작업을 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
previous_snapshot_id | BIGINT | 작업 전 현재 스냅샷의 ID |
current_snapshot_id | BIGINT | 작업 후 스냅샷 ID(snapshot_id 매개변수에서 가져오거나 ref 매개변수로부터 결정됨) |
예제:
-- Set current snapshot by snapshot ID
ALTER TABLE iceberg_db.iceberg_table
EXECUTE set_current_snapshot ("snapshot_id" = "123456789");
-- Set current snapshot by branch name
ALTER TABLE iceberg_db.iceberg_table
EXECUTE set_current_snapshot ("ref" = "feature_branch");
-- Set current snapshot by tag name
ALTER TABLE iceberg_db.iceberg_table
EXECUTE set_current_snapshot ("ref" = "v1.0");
참고 사항:
- 이 작업은 WHERE 조건을 지원하지 않습니다.
snapshot_id와ref매개변수는 상호 배타적이므로 하나만 지정할 수 있습니다.- 지정한 스냅샷 ID 또는 참조가 없으면 작업이 실패합니다.
- 현재 스냅샷이 이미 대상 스냅샷이면 새 스냅샷을 생성하지 않고 즉시 반환합니다.
publish_changes
publish_changes 작업은 WAP(Write-Audit-Publish) 모드에서 지정한 wap.id가 있는 스냅샷을 현재 테이블 상태로 게시하는 데 사용됩니다.
wap.id가 주어진 wap_id와 일치하는 스냅샷을 찾아 현재 테이블에 체리픽하여, 준비된 데이터를 모든 읽기 작업에서 볼 수 있게 합니다.
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE publish_changes("wap_id" = "<wap_id>")
매개변수:
매개변수:
| 매개변수 이름 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
wap_id | STRING | 예 | 게시할 WAP 스냅샷 ID |
반환값:
publish_changes를 실행하면 다음 2개 컬럼이 있는 결과 집합을 반환합니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
previous_snapshot_id | STRING | 게시 작업 전 현재 스냅샷의 ID(없으면 NULL) |
current_snapshot_id | STRING | 게시 후 새로 생성되어 현재 스냅샷으로 설정된 스냅샷의 ID |
예제:
-- Publish the snapshot whose WAP ID is test_wap_001
ALTER TABLE iceberg_db.iceberg_table
EXECUTE publish_changes("wap_id" = "test_wap_001");
참고 사항:
- 이 작업은 WHERE 절과 PARTITION/PARTITIONS 절을 지원하지 않습니다.
- write.wap.enabled = true가 설정되고 wap.id를 통해 WAP 스냅샷이 생성된 Iceberg 테이블에서만 의미가 있습니다.
- 지정한 wap_id에 해당하는 스냅샷을 찾지 못하면 작업이 실패하고 오류가 발생합니다.
- 게시 후 새 스냅샷이 현재 스냅샷이 됩니다.
- 게시 전에 스냅샷이 없으면 previous_snapshot_id는 NULL일 수 있습니다.
Iceberg 테이블 최적화
데이터 파일 분포 확인
다음 SQL로 Iceberg 테이블의 데이터 분포와 삭제 파일 수를 분석하여 rewrite_data_files와 같은 최적화가 필요한지 판단할 수 있습니다.
-
데이터 파일의 크기 분포를 표시합니다. 작은 파일이 너무 많은지 파악하는 데 도움이 됩니다.
SELECT
CASE
WHEN file_size_in_bytes BETWEEN 0 AND 8 * 1024 * 1024 THEN '0-8M'
WHEN file_size_in_bytes BETWEEN 8 * 1024 * 1024 + 1 AND 32 * 1024 * 1024 THEN '8-32M'
WHEN file_size_in_bytes BETWEEN 32 * 1024 * 1024 + 1 AND 128 * 1024 * 1024 THEN '32-128M'
WHEN file_size_in_bytes BETWEEN 128 * 1024 * 1024 + 1 AND 512 * 1024 * 1024 THEN '128-512M'
WHEN file_size_in_bytes > 512 * 1024 * 1024 THEN '> 512M'
ELSE 'Unknown'
END AS SizeRange,
COUNT(*) AS FileNum
FROM store_sales$data_files
GROUP BY
SizeRange;
+-----------+---------+
| SizeRange | FileNum |
+-----------+---------+
| 0-8M | 8 |
| 8-32M | 6 |
+-----------+---------+ -
데이터 파일과 삭제 파일의 수를 표시합니다.
SELECT
CASE
WHEN content = 0 THEN 'DataFile'
WHEN content = 1 THEN 'PositionDeleteFile'
WHEN content = 2 THEN 'EqualityDeleteFile'
ELSE 'Unknown'
END AS ContentType,
COUNT(*) AS FileNum,
SUM(file_size_in_bytes) AS SizeInBytes,
SUM(record_count) AS Records
FROM
iceberg_table$files
GROUP BY
ContentType;
+--------------------+---------+-------------+---------+
| ContentType | FileNum | SizeInBytes | Records |
+--------------------+---------+-------------+---------+
| EqualityDeleteFile | 2787 | 1432518 | 27870 |
| DataFile | 2787 | 4062416 | 38760 |
| PositionDeleteFile | 11 | 36608 | 10890 |
+--------------------+---------+-------------+---------+
Dangling Delete
일부 경우에는 rewrite_data_files 작업을 실행한 뒤에도 특정 Position Delete에 대한 참조가 스냅샷 메타데이터에서 제거되지 않을 수 있습니다(Dangling Delete). 이런 상황에서 메타데이터의 행 수 정보를 직접 사용하면 결과가 잘못될 수 있습니다.
따라서 기본적으로 COUNT(*) 쿼리에서 Position Delete 파일이 발견되면 COUNT 푸시다운 최적화를 활성화하지 않고 파일을 직접 읽어 실제 COUNT(*) 결과를 구합니다. 다만 이 방식은 시간이 오래 걸립니다.
Dangling Delete 문제가 없다고 보장할 수 있다면 Doris 세션 변수 ignore_iceberg_dangling_delete로 이 검사를 건너뛸 수 있습니다. 기본값은 false입니다. true로 설정하면 시스템이 메타데이터의 행 수 정보를 기반으로 COUNT(*) 결과를 직접 반환하여 쿼리 효율을 높입니다.
이 기능은 버전 3.1.4 및 4.0.3부터 지원됩니다.
부록
rewrite_data_files 파일 선택 전략
이 섹션에서는 다시 작성할 파일을 선택하는 로직을 설명합니다. 다음 SQL 쿼리로 시스템 테이블 정보를 분석하여 어떤 파일이 다시 작성될지도 확인할 수 있습니다. 실제 다시 작성 작업을 실행하기 전에 동작을 디버깅하고 이해하는 데 도움이 됩니다.
다시 작성 작업은 두 단계의 필터링 및 그룹화 전략을 사용합니다.
-
1단계: 파일 수준 필터링
먼저 파일 수준 조건으로 파일을 필터링합니다. 다음 조건 중 하나 이상을 만족하는 파일만 다시 작성 대상으로 고려합니다.
- 파일 크기가 범위를 벗어남: 파일이
min-file-size-bytes보다 작거나max-file-size-bytes보다 큽니다. - 삭제 파일이 너무 많음: 연결된 삭제 파일 수 >=
delete-file-threshold - 삭제 비율이 높음: 삭제 레코드 비율 >=
delete-ratio-threshold
삭제 파일 조건에 대한 참고 사항: 삭제 파일 관련 조건(
delete-file-threshold및delete-ratio-threshold)은 다시 작성할 파일 선택에 영향을 주지만, 시스템 테이블 SQL 쿼리로 정확히 계산할 수는 없습니다. 현재 시스템 테이블 정보만으로는 삭제 파일이 어떤 데이터 파일에 영향을 주는지 정확히 판단하기 어렵기 때문입니다. 삭제 파일은 특정 데이터 파일에만 영향을 줄 수 있으며(특히 Position Delete 파일), 삭제 파일과 데이터 파일 사이의 연결 관계를 파악하려면 현재 시스템 테이블에서 제공하지 않는 더 상세한 메타데이터가 필요합니다. 실제 다시 작성 작업은 시스템 테이블에 노출되지 않는 상세 메타데이터를 기반으로 이 조건들을 평가합니다. - 파일 크기가 범위를 벗어남: 파일이
-
2단계: BinPack 그룹화 및 그룹 수준 필터링
파일 수준 필터링 후 파일을 파티션별로 그룹화합니다. 그런 다음 각 파티션 안에서 파일 크기와
max-file-group-size-bytes를 기준으로 BinPack 알고리즘을 사용하여 파일을 그룹화합니다. BinPack 알고리즘은 다시 작성 작업을 최적화하도록 파일을 그룹에 효율적으로 배치합니다.그룹화 후에는 그룹 수준 조건으로 파일 그룹을 필터링합니다. 다음 조건 중 하나 이상을 만족하는 파일 그룹이 다시 작성됩니다.
- 입력 파일 수가 충분함: 그룹 내 파일 수 > 1이고 파일 수 >=
min-input-files - 데이터 양이 충분함: 그룹 내 파일 수 > 1이고 전체 크기 >
target-file-size-bytes - 데이터 양이 너무 많음: 그룹 전체 크기 >
max-file-group-size-bytes - 삭제 파일 문제가 있는 파일 포함: 그룹에 삭제 파일이 너무 많거나 삭제 비율이 높은 파일이 하나 이상 있습니다.
BinPack 그룹화에 대한 참고 사항: 각 파티션 내에서 파일을 그룹화하는 BinPack 알고리즘은 복잡한 최적화 알고리즘이므로 시스템 테이블 SQL 쿼리로 정확히 모사할 수 없습니다. 이 알고리즘은 파일 크기와
max-file-group-size-bytes를 고려하여 파일을 그룹에 효율적으로 배치하므로, 단순한 파티션 기반 그룹화와 결과가 다를 수 있습니다. 따라서 아래 SQL 쿼리는 파일 수준 조건을 만족하는 파일만 식별할 수 있으며, 최종적으로 다시 작성할 파일 그룹을 정확히 계산할 수는 없습니다. - 입력 파일 수가 충분함: 그룹 내 파일 수 > 1이고 파일 수 >=
다음은 쿼리 전략의 예입니다.
-
쿼리 1: 파일 수준 조건을 만족하는 파일 식별
이 쿼리는 파일 수준 조건(파일 크기)을 만족하여 다시 작성 대상으로 고려되는 파일을 식별합니다.
-- Set parameters (adjust according to your rewrite parameters)
SET @min_file_size_bytes = 16 * 1024 * 1024; -- 16 MB (default: target-file-size-bytes * 0.75)
SET @max_file_size_bytes = 768 * 1024 * 1024; -- 768 MB (default: target-file-size-bytes * 1.8)
SELECT
file_path,
`partition`,
file_size_in_bytes / 1024.0 / 1024.0 AS file_size_mb,
record_count,
CASE
WHEN file_size_in_bytes < @min_file_size_bytes THEN 'Too small'
WHEN file_size_in_bytes > @max_file_size_bytes THEN 'Too large'
END AS size_issue
FROM iceberg_table$data_files
WHERE file_size_in_bytes < @min_file_size_bytes
OR file_size_in_bytes > @max_file_size_bytes
ORDER BY `partition`, file_size_in_bytes DESC;출력 예:
+----------------------------------------------------------------------------------------+---------------------------+-------------+--------------+------------+
| file_path | partition | file_size_mb | record_count | size_issue |
+----------------------------------------------------------------------------------------+---------------------------+-------------+--------------+------------+
| s3a://bucket/path/to/table/data/date_col=2024-01-01/00000-0-00000-00000-0.parquet | {"date_col":"2024-01-01"} | 0.00215 | 5 | Too small |
| s3a://bucket/path/to/table/data/date_col=2024-01-01/00001-0-00001-00001-0.parquet | {"date_col":"2024-01-01"} | 0.00198 | 5 | Too small |
| s3a://bucket/path/to/table/data/date_col=2024-01-02/00002-0-00002-00002-0.parquet | {"date_col":"2024-01-02"} | 0.00231 | 5 | Too small |
| s3a://bucket/path/to/table/data/date_col=2024-01-02/00003-0-00003-00003-0.parquet | {"date_col":"2024-01-02"} | 850.23456 | 1250000 | Too large |
| s3a://bucket/path/to/table/data/date_col=2024-01-03/00004-0-00004-00004-0.parquet | {"date_col":"2024-01-03"} | 0.00245 | 5 | Too small |
+----------------------------------------------------------------------------------------+---------------------------+-------------+--------------+------------+
5 rows in set참고: 이 쿼리는 파일 수준 조건(파일 크기)을 만족하는 파일만 식별합니다. 실제 다시 작성할 파일 그룹은 BinPack 그룹화 알고리즘에 따라 결정되며, SQL 쿼리로 정확히 모사할 수 없습니다. 이 쿼리로 식별한 파일도 BinPack 알고리즘에 의해 다르게 그룹화될 수 있고, 일부 그룹은 그룹 수준 조건에 따라 제외될 수 있습니다.
-
쿼리 2: 전체 통계 요약
이 쿼리는 파일 수준 조건을 만족하는 파일의 전체 통계를 제공합니다.
-- Set parameters (adjust according to your rewrite parameters)
SET @min_file_size_bytes = 16 * 1024 * 1024;
SET @max_file_size_bytes = 768 * 1024 * 1024;
WITH file_analysis AS (
SELECT
`partition`,
file_path,
file_size_in_bytes,
record_count,
(file_size_in_bytes < @min_file_size_bytes OR file_size_in_bytes > @max_file_size_bytes) AS meets_file_level_conditions
FROM iceberg_table$data_files
)
SELECT
'Total files' AS metric,
COUNT(*) AS value
FROM file_analysis
UNION ALL
SELECT
'Files meeting file-level conditions',
SUM(CASE WHEN meets_file_level_conditions THEN 1 ELSE 0 END)
FROM file_analysis
UNION ALL
SELECT
'Total size (GB)',
ROUND(SUM(file_size_in_bytes) / 1024.0 / 1024.0 / 1024.0, 2)
FROM file_analysis
UNION ALL
SELECT
'Size meeting file-level conditions (GB)',
ROUND(SUM(CASE WHEN meets_file_level_conditions THEN file_size_in_bytes ELSE 0 END) / 1024.0 / 1024.0 / 1024.0, 2)
FROM file_analysis
UNION ALL
SELECT
'Percentage meeting file-level conditions (%)',
ROUND(SUM(CASE WHEN meets_file_level_conditions THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2)
FROM file_analysis;출력 예:
+----------------------------------------------+--------+
| metric | value |
+----------------------------------------------+--------+
| Total files | 15.00 |
| Total size (GB) | 2.45 |
| Files meeting file-level conditions | 12.00 |
| Size meeting file-level conditions (GB) | 1.85 |
| Percentage meeting file-level conditions (%) | 80.00 |
+----------------------------------------------+--------+
5 rows in set참고 사항:
- 예제의
iceberg_table을 실제 테이블 이름으로 바꾸세요. - 매개변수 값(
@min_file_size_bytes,@max_file_size_bytes)을 실제 다시 작성 매개변수에 맞게 조정하세요. - 위에 표시된 기본값은 기본 다시 작성 매개변수(min-file-size-bytes = target-file-size-bytes * 0.75, max-file-size-bytes = target-file-size-bytes * 1.8)에 대응합니다.
- 예제의
-
스냅샷과 브랜치의 관계 확인:
SELECT
refs_data.snapshot_id,
snapshots.committed_at,
snapshots.operation,
ARRAY_SORT(refs_data.refs)
FROM (
SELECT
snapshot_id,
ARRAY_AGG(CONCAT(type, ':', name)) AS refs
FROM
iceberg_table$refs
GROUP BY
snapshot_id
) AS refs_data
JOIN (
SELECT
snapshot_id,
committed_at,
operation
FROM
iceberg_table$snapshots
) AS snapshots
ON refs_data.snapshot_id = snapshots.snapshot_id
ORDER BY
snapshots.committed_at;
+---------------------+----------------------------+-----------+-------------------------------------+
| snapshot_id | committed_at | operation | ARRAY_SORT(refs_data.refs) |
+---------------------+----------------------------+-----------+-------------------------------------+
| 8272911997874079853 | 2025-07-10 15:27:07.177000 | append | ["BRANCH:b1", "TAG:t1"] |
| 1325777059626757917 | 2025-07-10 15:27:07.530000 | append | ["BRANCH:b2", "TAG:t2"] |
| 76492482642020578 | 2025-07-10 15:27:07.865000 | append | ["BRANCH:b3", "TAG:t3"] |
| 1788715857849070138 | 2025-07-12 04:15:19.626000 | append | ["BRANCH:main", "TAG:t4", "TAG:t5"] |
+---------------------+----------------------------+-----------+-------------------------------------+