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의 warehouse 경로입니다. 이 매개변수는
<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-enabled4.0.6 버전부터 지원됩니다.
Iceberg REST Catalog에서만 유효합니다. 뷰 관련 작업(
listViews,loadView,viewExists,dropView등)을 활성화할지 지정합니다. 기본값은true입니다.일부 Iceberg REST Catalog 구현은 테이블 API를 제공하지만 뷰 API를 사용할 수 없거나 뷰 API가 오류를 반환합니다. Doris는
SHOW TABLES를 실행할 때ViewCatalog.listViews()를 호출하여 테이블 목록에서 뷰를 제외하므로, 이러한 REST 서비스에서는SHOW TABLES와 테이블 메타데이터 로딩이 실패할 수 있습니다.이 경우 이 매개변수를
false로 설정하면 Doris가 모든 뷰 관련 작업을 건너뛰어SHOW TABLES등의 메타데이터 작업을 정상적으로 수행할 수 있습니다.
-
-
{CommonProperties}CommonProperties 영역에는 일반 속성을 입력합니다. 공통 속성에 대한 자세한 내용은 Catalog 개요를 참고하세요.
메타데이터 캐시
Apache Doris는 외부 데이터 소스 접근 성능을 높이기 위해 Iceberg 메타데이터를 캐시합니다. 메타데이터에는 로드된 테이블 메타데이터, 파티션 데이터, manifest, 파생 파티션 프로젝션, 최신 스냅샷 ID, 추론된 파일 형식이 포함됩니다.
Doris 4.1.x 이전 버전에서는 주로 FE 구성 항목을 통해 메타데이터 캐시를 전역으로 제어합니다. 자세한 내용은 메타데이터 캐시를 참고하세요.
Doris 4.1.x부터 Iceberg Catalog의 외부 메타데이터 캐시는 통합 meta.cache.* 키를 사용하여 구성합니다. 아래 항목은 현재 버전에 대한 설명입니다. Doris 4.1.x 및 4.2.x는 다른 항목 집합을 사용하며, 해당 내용은 이 페이지의 4.x 버전에 설명되어 있습니다.
캐시 속성 구성
각 캐시 항목은 통합 구성 키 형식인 meta.cache.<engine>.<entry>.{enable,ttl-second,capacity,max-weight}를 사용합니다. Iceberg의 경우 <engine>은 iceberg입니다. meta.cache.iceberg.table.ttl-second는 공유 TTL 설정으로, table 및 partition 항목의 기본 TTL과 자체 <entry> 토큰이 없는 캐시의 TTL을 지정합니다. 값을 0으로 설정하면 이 캐시가 모두 비활성화되므로, 모든 쿼리가 최신 스냅샷을 실시간으로 읽습니다.
| 속성 | 예제 | 의미 |
|---|---|---|
enable | true/false | 이 캐시 항목을 활성화할지 지정합니다. |
ttl-second | 600, 0, -1 | 0은 항목을 비활성화합니다(즉시 적용되며 최신 데이터를 확인하는 데 사용할 수 있음). -1은 만료되지 않음을 의미합니다. 그 밖의 양의 정수는 접근 시간을 기준으로 하는 TTL을 초 단위로 지정합니다. |
capacity | 10000 | 개수 기준 최대 캐시 항목 수입니다. 0은 항목을 비활성화합니다. |
max-weight | 1GB | Doris 4.1.4부터 지원됩니다. 항목이 유지하는 메모리 추정량의 한도를 선택적으로 지정합니다. 양수여야 하며 0은 허용되지 않습니다. 아래에 표시된 항목에서만 사용할 수 있습니다. |
적용 로직: enable=true, ttl-second != 0, capacity > 0인 경우 항목이 적용됩니다. FE 전체, Catalog 또는 항목 수준의 메모리 한도도 추정 메모리를 기준으로 캐시 수용 여부를 제어합니다. 외부 메타데이터 캐시 메모리 관리를 참고하세요.
캐시 모듈
다음 항목은 자체 구성 키를 가지며 max-weight를 지원합니다.
항목 (<entry>) | 속성 키 접두사 | ENTRY_NAME | 캐시되는 내용 및 효과 | 기본 활성화 여부 / TTL / 용량 |
|---|---|---|---|---|
table | meta.cache.iceberg.table. | iceberg-table | 로드된 Iceberg 테이블 메타데이터입니다. 효과: Catalog 왕복 요청과 메타데이터 파일 읽기를 줄입니다. | true / 86400 s / 1000 |
partition | meta.cache.iceberg.partition. | iceberg-partition | 테이블 스냅샷의 원시 파티션 데이터입니다. | true / table과 동일 / 1000 |
manifest | meta.cache.iceberg.manifest. | iceberg-manifest | 파싱된 manifest 내용입니다. 스캔 계획에서는 enable이 true인 경우에만 사용하며, 기본값은 false입니다. | 캐시 자체는 true, 사용 여부는 false / 만료 없음 / 100000 |
partition_view | meta.cache.iceberg.partition_view. | iceberg.mvcc-partition-view, iceberg.list-partitions-view | 하나의 항목 한도를 공유하는 두 개의 파생 파티션 프로젝션입니다. | true / 86400 s / 1000 |
다음 캐시에는 <entry> 토큰이 없습니다. Catalog 및 FE 전체 메모리 한도를 따르며, TTL은 meta.cache.iceberg.table.ttl-second에서 가져옵니다. iceberg-latest-snapshot(최신 스냅샷 ID), iceberg-format(추론된 파일 형식), iceberg-comment(테이블 주석, 발급된 자격 증명을 사용하는 REST Catalog에서만 생성됨), iceberg-equality-delete-field-ids가 이에 해당합니다.
Iceberg 테이블의 컬럼 스키마는 공유 default 엔진(meta.cache.default.schema.*)에 캐시됩니다.
iceberg.rest.session이 user이면 table, partition, partition_view, latest-snapshot, format 캐시는 생성되지 않습니다. 공유 캐시가 사용자별 권한 검사를 우회할 수 있기 때문입니다. 발급된 자격 증명을 사용하는 REST Catalog도 table 캐시를 생성하지 않습니다.
기존 매개변수 매핑 및 변환
| 기존 속성 키 | 통합 키 | 설명 |
|---|---|---|
schema.cache.ttl-second | meta.cache.default.schema.ttl-second | 테이블 스키마 캐시의 만료 시간 |
모범 사례
- 최신 데이터에 실시간 접근: 각 쿼리에서 Iceberg 테이블의 최신 스냅샷을 확인하려면
meta.cache.iceberg.table.ttl-second를0으로 설정합니다.-- Disable the table, partition, latest-snapshot, and format caches to read the latest snapshot live
ALTER CATALOG iceberg_ctl SET PROPERTIES ("meta.cache.iceberg.table.ttl-second" = "0"); - 성능 최적화:
- manifest 캐시를 활성화하면 대규모 테이블의 쿼리 계획 수립 속도를 크게 높일 수 있습니다. manifest가 크면
max-weight로 메모리 사용량을 제한합니다.ALTER CATALOG iceberg_ctl SET PROPERTIES (
"meta.cache.iceberg.manifest.enable" = "true",
"meta.cache.iceberg.manifest.max-weight" = "1GB"
); - Catalog 속성 변경에 성공하면 영향을 받는 메타데이터 캐시를 삭제하고 다음 접근 시 새 구성으로 다시 생성합니다.
meta.cache.max-weight또는schema.cache.ttl-second를 변경하면 해당 Catalog의 모든 캐시를 삭제합니다.meta.cache.<engine>.<entry>.*를 변경하면 해당 엔진의 캐시를 삭제합니다. 이미 진행 중인 쿼리에는 영향을 주지 않습니다.
- manifest 캐시를 활성화하면 대규모 테이블의 쿼리 계획 수립 속도를 크게 높일 수 있습니다. manifest가 크면
관측 가능성
캐시 지표는 information_schema.catalog_meta_cache_statistics 시스템 테이블에서 확인할 수 있습니다. ENTRY_NAME은 위 표에 나열된 이름을 표시하며, default 엔진 행은 공유 테이블 스키마 캐시입니다.
SELECT engine_name, entry_name,
effective_enabled, ttl_second, capacity,
estimated_size, hit_rate, max_weight, estimated_weight
FROM information_schema.catalog_meta_cache_statistics
WHERE catalog_name = 'iceberg_ctl'
ORDER BY engine_name, 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 |
| dev (master) | 1.12.0 |
메타데이터 및 읽기 오류(4.1.5부터)
DESCRIBE,SHOW COLUMNS,SHOW CREATE TABLE은 현재 Iceberg 스키마의 필수/선택 선언을 유지합니다. 스캔은 스키마 진화로 누락된 필드를 계속 처리합니다. NOT NULL 선언이 표시되더라도 모든 과거 파일에 해당 필드가 존재한다는 의미는 아닙니다.- dev 버전은 행 수준 쓰기 파티션 메타데이터를 직렬화된 파티션 데이터로 전달합니다. 4.1.5의 오류
Cannot produce Iceberg row IDs with unsupported partition types in spec ...는 이전 Row ID 표현 방식에 대한 설명이며 현재 표현 방식에는 적용되지 않습니다. - 커밋된 스냅샷이 참조하는 데이터 파일 또는 삭제 파일이 없으면
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 | ✅ | ✅ | ✅ | ✅ | ✅ |
labels 시스템 테이블은 5.0.0 버전부터 지원되며 Iceberg REST Catalog에서만 사용할 수 있습니다. 자세한 내용은 아래 labels를 참조하세요.
지원되는 스토리지 시스템
- 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 테이블도 정상적으로 쿼리할 수 있습니다.
4.1.4 버전부터 Iceberg identity 파티션 메타데이터가 모든 split과 함께 전달되며, 경로 파티션 키는 테이블의 모든 파티션 spec에 있는 identity 컬럼을 포함합니다. 따라서 Partition Evolution을 거친 테이블에서도 파티션 컬럼 값이 올바르게 반환됩니다.
컬럼 유형 매핑
Doris 4.2의 전체 데이터 유형 매핑 표, 정밀도 규칙 및 지원되지 않는 유형은 Iceberg와 Doris 간 데이터 유형 매핑을 참조하세요.
컬럼 이름의 대소문자
Doris는 Iceberg 테이블 컬럼 이름의 원래 대소문자를 유지하며, 읽을 때는 대소문자를 구분하지 않고 컬럼을 일치시킵니다. 대문자가 포함되거나 대소문자가 혼합된 컬럼 이름(예: UserId 또는 ORDER_ID)도 정상적으로 쿼리할 수 있습니다.
4.0 계열의 4.0.8 이전 버전은 읽을 때 정확히 일치하는 이름으로 컬럼을 찾았으므로, 대소문자가 혼합된 컬럼 이름을 가진 Iceberg 및 Paimon 테이블에서 잘못된 컬럼을 읽거나 쿼리가 실패할 수 있었습니다. 이 문제는 4.0.8에서 수정되었습니다.
Namespace 매핑
Iceberg의 메타데이터 계층 구조는 Catalog -> Namespace -> 테이블입니다. 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를 활성화하지 않았다면 업그레이드 후 검증이 실패하므로 해당 속성을 추가해야 합니다.
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;
파일 메타데이터 컬럼
4.2.0 버전부터 지원됩니다.
Doris는 Iceberg 데이터 테이블에 두 개의 숨겨진 메타데이터 컬럼을 제공합니다. 이 컬럼으로 각 쿼리 결과가 나온 물리적 데이터 파일과 행을 찾을 수 있습니다.
| 컬럼 | 유형 | 설명 |
|---|---|---|
_file | STRING NOT NULL | Iceberg 데이터 파일에 기록된 원래 경로입니다. |
_pos | BIGINT NOT NULL | 전체 데이터 파일 내에서 영부터 시작하는 물리적 행 위치입니다. |
사전 요구 사항: 앞의 예제에 따라 Iceberg Catalog를 구성하고, id 컬럼을 포함하며 Parquet 또는 ORC 파일을 사용하는 Iceberg 데이터 테이블을 생성합니다. 다음 쿼리는 iceberg_tbl에 id 값이 1과 2인 행이 이미 있다고 가정합니다.
SELECT id, `_file`, `_pos`
FROM iceberg.iceberg_db.iceberg_tbl
ORDER BY `_file`, `_pos`;
결과 예제(파일 경로는 테이블 위치에 따라 다름):
+----+---------------------------------------+------+
| id | _file | _pos |
+----+---------------------------------------+------+
| 1 | s3://bucket/warehouse/db/table/a.orc | 0 |
| 2 | s3://bucket/warehouse/db/table/a.orc | 1 |
+----+---------------------------------------+------+
기본적으로 이 컬럼은 SELECT * 또는 DESC에 표시되지 않습니다.
숨겨진 컬럼을 SELECT * 및 DESC에 포함하려면 세션에서 show_hidden_columns를 활성화합니다.
SET show_hidden_columns = true;
관련 세션 변수:
| 변수 | 유형 | 기본값 | 필수 여부 | 효과 |
|---|---|---|---|---|
show_hidden_columns | BOOLEAN | false | 아니요 | 숨겨진 컬럼을 SELECT * 및 DESC에 포함합니다. 컬럼을 명시적으로 참조할 때는 필요하지 않습니다. |
enable_file_scanner_v2 | BOOLEAN | true | 아니요 | 쿼리가 이 메타데이터 컬럼을 참조할 때는 활성화 상태를 유지해야 합니다. |
force_jni_scanner | BOOLEAN | false | 아니요 | JNI 리더는 이 메타데이터 컬럼을 생성할 수 없으므로 비활성화 상태를 유지해야 합니다. |
행 위치는 전체 물리적 파일을 기준으로 합니다. 조건자 필터링, 삭제 처리, 스캔 분할을 수행해도 나머지 행의 번호는 다시 매겨지지 않습니다. 따라서 _file과 _pos를 조합하면 현재 테이블 스냅샷에서 물리적 레코드를 찾을 수 있습니다. 데이터 파일 재작성이나 compaction으로 두 값이 모두 변경될 수 있으므로, 안정적인 논리적 행 ID로 사용해서는 안 됩니다.
이 컬럼은 FileScannerV2 네이티브 Parquet 또는 ORC 리더로 Iceberg 데이터 테이블을 읽을 때만 사용할 수 있습니다. enable_file_scanner_v2가 비활성화되어 있거나, force_jni_scanner가 활성화되어 있거나, 선택된 데이터 파일에서 네이티브 Parquet/ORC 리더를 사용할 수 없으면 이 컬럼을 참조하는 쿼리는 실패합니다.
_file과 _pos는 대소문자를 구분하지 않는 예약된 이름입니다. Iceberg 테이블의 물리적 컬럼 이름으로 사용하지 마세요.
시간 여행
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는 초의 소수부 1자리부터 9자리까지를 yyyy-MM-dd HH:mm:ss 뒤에 지정할 수 있으며, 값을 세션 시간대로 해석하고 스냅샷 선택을 위해 밀리초로 변환합니다. 예를 들어 FOR TIME AS OF '2024-01-01 12:00:00.123456'을 사용합니다. 스냅샷 선택의 정밀도는 밀리초이며, 이 구문을 허용한다고 해서 나노초 단위 스냅샷 시각이 유지되는 것은 아닙니다.
Doris 4.1.5에서는 컬럼 이름 변경, 삭제, 유형 승격, 파티션 진화 이후의 과거 스냅샷 읽기 문제도 수정되었습니다. 각 파일은 현재 spec만 사용하는 대신 파일이 작성될 때 활성화되어 있던 파티션 spec으로 해석됩니다. 과거 데이터를 조회하는 쿼리가 현재 구체화된 뷰를 읽도록 재작성되어서는 안 됩니다.
Branch 및 Tag
3.1.0부터 지원됩니다.
Branch 및 Tag 생성, 삭제, 관리에 대해서는 [Branch 및 Tag 관리] 절을 참고하세요.
Iceberg 테이블의 특정 Branch 및 Tag 읽기를 지원합니다.
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는 매개변수가 타임스탬프인지 Branch/Tag 이름인지 자동으로 판단합니다.
뷰
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 invisible 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 requires a target column reference또는Cannot find column information for DEFAULT(<col>)오류가 발생합니다. - 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>및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 버전부터 지원됩니다.
labels시스템 테이블은 5.0.0 버전부터 지원되며 Iceberg REST Catalog에서만 사용할 수 있습니다.
4.1.4 버전부터 Iceberg 시스템 테이블은 네이티브 실행 경로를 통해 쿼리되며, 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 |
+----------------------------+---------------------+---------------------+---------------------+
labels
이 기능은 5.0.0 버전부터 지원됩니다.
REST Catalog가 Iceberg 테이블에 제공하는 테이블 수준(object) 및 필드 수준(field) 라벨을 표시합니다. 라벨의 키-값 쌍마다 한 행이 표시됩니다. 테이블 소유권이나 필드의 데이터 분류 등의 정보를 확인할 때 사용합니다.
이 시스템 테이블은 iceberg.catalog.type이 rest일 때만 사용할 수 있습니다. Doris에서 추가로 설정할 항목은 없습니다. REST Catalog 서비스는 테이블을 로드할 때 라벨을 반환하며, 라벨의 생성과 수정은 서비스 제공자를 통해 수행합니다. 이 라벨은 테이블이나 필드를 설명하며 refs에 표시되는 스냅샷 Tag와는 별개입니다.
필드:
| 필드 | 유형 | 설명 |
|---|---|---|
scope | TEXT | 라벨의 적용 범위입니다. 테이블 수준 라벨은 object, 필드 수준 라벨은 field입니다. |
field_id | INT | Iceberg 필드 ID입니다. 테이블 수준 라벨에서는 NULL입니다. |
field_name | TEXT | 현재 테이블 스키마를 기준으로 확인한 필드 이름입니다. 중첩 필드는 address.city처럼 전체 경로를 사용합니다. 테이블 수준 라벨이거나 필드 ID가 현재 스키마에 없으면 NULL입니다. |
key | TEXT | 라벨 키입니다. key는 Doris의 예약어이므로 SQL에서 이 열을 명시적으로 참조할 때는 백틱으로 감싸야 합니다. |
value | TEXT | 라벨 값입니다. |
쿼리 예시:
다음 예시는 iceberg_ctl Catalog가 Iceberg REST Catalog에 설명된 대로 설정되어 있고, iceberg_db.iceberg_tbl 테이블이 존재하며, 현재 사용자에게 이 테이블을 쿼리할 권한이 있다고 가정합니다. REST Catalog 서비스에는 다음 라벨이 설정되어 있으며, 서비스가 이를 반환합니다:
- 테이블 수준 라벨:
owner=team-a. email필드(필드 ID2)의 라벨:classification=pii.- 중첩 필드
address.city(필드 ID5)의 라벨:classification=location.
모든 라벨을 적용 범위, 필드 ID, 라벨 키 순으로 정렬하여 쿼리합니다:
SELECT * FROM iceberg_ctl.iceberg_db.iceberg_tbl$labels
ORDER BY scope, field_id, `key`;
결과:
+--------+----------+--------------+----------------+----------+
| scope | field_id | field_name | key | value |
+--------+----------+--------------+----------------+----------+
| field | 2 | email | classification | pii |
| field | 5 | address.city | classification | location |
| object | NULL | NULL | owner | team-a |
+--------+----------+--------------+----------------+----------+
pii로 분류된 필드를 찾습니다:
SELECT field_name, `key`, value
FROM iceberg_ctl.iceberg_db.iceberg_tbl$labels
WHERE scope = 'field' AND `key` = 'classification' AND value = 'pii';
결과:
+------------+----------------+-------+
| field_name | key | value |
+------------+----------------+-------+
| email | classification | pii |
+------------+----------------+-------+
캐싱 및 새로고침:
라벨은 테이블 메타데이터와 함께 캐시되며 meta.cache.iceberg.table.ttl-second 설정을 따릅니다. 서비스에서 라벨을 변경한 후 업데이트된 라벨을 가져오려면 $labels를 쿼리하기 전에 원본 테이블을 새로고침하세요:
REFRESH TABLE iceberg_ctl.iceberg_db.iceberg_tbl;
새로고침 후 다음 $labels 쿼리는 테이블을 다시 로드하고 서비스가 반환한 라벨을 읽습니다. meta.cache.iceberg.table.ttl-second를 0으로 설정하면 테이블 메타데이터 캐시가 비활성화되어 쿼리마다 라벨을 다시 로드합니다. 캐시 설정에 대한 자세한 내용은 메타데이터 캐시를 참조하세요.
참고:
- REST Catalog 서비스가 라벨을 반환하지 않으면 쿼리 결과는 비어 있습니다. 스냅샷이 없는 테이블도 서비스가 라벨을 제공하면 라벨을 반환할 수 있습니다.
COUNT(*)는 원본 테이블의 데이터 행이 아닌 라벨 키-값 쌍의 수를 셉니다. - 라벨은 스냅샷별로 버전이 관리되지 않습니다.
$labels에FOR VERSION AS OF를 사용해도 과거 라벨을 가져올 수 없습니다. 쿼리는 여전히 현재 로드된 테이블의 라벨을 반환하며, 필드 이름은 현재 스키마를 기준으로 확인합니다. - 필드 라벨은 필드 ID와 연결됩니다. 필드 이름이 변경되면
field_name에 새 이름이 표시됩니다. 필드가 삭제된 후에도 서비스가 해당 라벨을 반환한다면field_id는 유지되고field_name은NULL이 됩니다. - REST Catalog가 아닌 Catalog는
$labels를 지원하지 않으며, 이를 쿼리하면Unknown sys table오류가 반환됩니다. 서버 측 스캔 계획이 필요한 REST Catalog도 이 시스템 테이블을 지원하지 않습니다.
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
테이블의 알려진 모든 스냅샷 참조(Branch 및 Tag)를 표시합니다.
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 버전부터 지정된 Branch에 데이터 쓰기를 지원합니다.
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 버전부터 지정된 Branch에 데이터 쓰기를 지원합니다.
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 형식 테이블에서 실행하면 시스템은 Puffin 형식의 Deletion Vectors로 기존 Position Delete 데이터를 대체할 뿐 아니라, 내용 갱신이 포함된 경우 기록된 레코드의 계보 수명 주기 속성(_last_updated_sequence_number)도 자동으로 조정합니다. - 이러한 작업은 Parquet 및 ORC 파일 형식을 모두 지원합니다.
- 동시 쓰기 시나리오에서 Iceberg는 낙관적 동시성 제어 메커니즘을 제공합니다. 쓰기 충돌이 발생하면 작업에서 트랜잭션 충돌 예외가 발생할 수 있습니다.
UPDATE작업은 독립적으로 실행하거나MERGE INTO내에서 실행할 때 모두age = age * 2 + 1또는name = concat(name, '-modified')같은 표현식과 함수 사용을 지원합니다.- 이러한 작업은 파티션 테이블과 비파티션 테이블에 모두 적용됩니다.
- 4.1.4 버전부터
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 비파티션 테이블에서 scaling-write를 시작하는 데이터 임계값입니다. 데이터가 table_sink_non_partition_write_scaling_data_processed_threshold만큼 추가될 때마다 새 writer(인스턴스)를 사용합니다. 이 메커니즘은 데이터 볼륨에 따라 writer 수를 조정하여 처리량을 높이고, 데이터 볼륨이 작을 때는 리소스를 절약하고 파일 수를 최소화합니다.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;
정규화된 전체 이름으로 데이터베이스를 생성하거나 위치를 지정할 수도 있습니다(현재 위치 지정은 HMS 유형의 Catalog에서만 지원). 예를 들면 다음과 같습니다.
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/');
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.0.2 버전부터 Doris는 ALTER 문을 통한 Iceberg 테이블의 Partition Evolution을 지원합니다.
지원되는 파티션 변환은 다음과 같습니다.
| 변환 | 구문 | 예제 |
|---|---|---|
| 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;
Branch 및 Tag 관리
3.1.0부터 지원
-
Branch 생성
구문:
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; -
Branch 삭제
구문:
ALTER TABLE [catalog.][database.]table_name
DROP BRANCH [IF EXISTS] <branch_name>;예제:
ALTER TABLE tbl DROP BRANCH b1; -
Tag 생성
구문:
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; -
Tag 삭제
구문:
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로 설정하면 사용하지 않는 파티션 spec과 스키마를 정리합니다. |
반환값:
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 작업은 한 Branch의 현재 스냅샷을 다른 Branch의 최신 스냅샷으로 빠르게 이동합니다.
지원 버전: 4.0.2+
구문:
ALTER TABLE [catalog.][database.]table_name
EXECUTE fast_forward ("branch" = "<branch_name>", "to" = "<target_branch>")
매개변수:
| 매개변수 | 유형 | 필수 여부 | 설명 |
|---|---|---|---|
branch | String | 예 | 이동할 Branch 이름 |
to | String | 예 | 대상 Branch 이름. branch가 이 Branch의 최신 스냅샷으로 이동합니다. |
반환값:
fast_forward 작업을 실행하면 다음 3개 컬럼으로 구성된 결과 집합이 반환됩니다.
| 컬럼 이름 | 유형 | 설명 |
|---|---|---|
branch_updated | STRING | 이동한 Branch의 이름 |
previous_ref | BIGINT | 이동 전에 Branch가 가리키던 스냅샷 ID(NULL일 수 있음) |
updated_ref | BIGINT | 이동 후 Branch가 가리키는 스냅샷 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 조건을 지원하지 않습니다.
- 지정된 Branch가 없으면 작업이 실패합니다.
- Branch만 이동할 수 있으며 Tag는 이동할 수 없습니다.
publish_changes
publish_changes 작업은 Write-Audit-Publish(WAP) 패턴의 "Publish" 단계입니다. 이 프로세스는 특정 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 | 출력 파일의 파티션 spec 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 또는 참조(Branch 또는 Tag)로 설정합니다.
지원 버전: 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 | 둘 중 하나 | 현재 스냅샷으로 설정할 참조 이름(Branch 또는 Tag) |
반환값:
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와 일치하는 스냅샷을 찾아 현재 테이블에 cherry-pick하여, 모든 읽기 작업에서 스테이징된 데이터를 볼 수 있게 합니다.
구문:
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).
- 예제의
-
스냅샷과 Branch 관계 확인:
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"] |
+---------------------+----------------------------+-----------+-------------------------------------+