메인 콘텐츠로 건너뛰기
Amazon S3, Azure, HDFS 또는 로컬에 저장된 Apache Iceberg 테이블에 테이블 형태의 읽기 전용 인터페이스를 제공합니다.

구문

icebergS3(url [, NOSIGN | access_key_id, secret_access_key, [session_token]] [,format] [,compression_method] [,extra_credentials])
icebergS3(named_collection[, option=value [,..]])

icebergAzure(connection_string|storage_account_url, container_name, blobpath, [,account_name], [,account_key] [,format] [,compression_method])
icebergAzure(named_collection[, option=value [,..]])

icebergHDFS(path_to_table, [,format] [,compression_method])
icebergHDFS(named_collection[, option=value [,..]])

icebergLocal(path_to_table, [,format] [,compression_method])
icebergLocal(named_collection[, option=value [,..]])

인수

인수 설명은 각각 테이블 함수 s3, azureBlobStorage, HDFS, file의 인수 설명과 동일합니다. format은 Iceberg 테이블의 데이터 파일 포맷을 나타냅니다. icebergS3에서는 선택적 extra_credentials 매개변수를 사용하여 ClickHouse Cloud에서 역할 기반 접근을 위한 role_arn을 전달할 수 있습니다. 구성 단계는 Secure S3를 참조하십시오.

반환 값

지정된 Iceberg 테이블의 데이터를 읽기 위한, 지정된 구조의 테이블을 반환합니다.

예시

SELECT * FROM icebergS3('http://test.s3.amazonaws.com/clickhouse-bucket/test_table', 'test', 'test')
ClickHouse는 현재 icebergS3, icebergAzure, icebergHDFSicebergLocal 테이블 함수와 IcebergS3, icebergAzure, IcebergHDFSIcebergLocal 테이블 엔진을 통해 Iceberg 포맷 v1 및 v2를 읽는 기능을 지원합니다.

명명된 컬렉션 정의하기

다음은 URL과 자격 증명을 저장할 명명된 컬렉션을 구성하는 예시입니다:
<clickhouse>
    <named_collections>
        <iceberg_conf>
            <url>http://test.s3.amazonaws.com/clickhouse-bucket/</url>
            <access_key_id>test<access_key_id>
            <secret_access_key>test</secret_access_key>
            <format>auto</format>
            <structure>auto</structure>
        </iceberg_conf>
    </named_collections>
</clickhouse>
SELECT * FROM icebergS3(iceberg_conf, filename = 'test_table')
DESCRIBE icebergS3(iceberg_conf, filename = 'test_table')

데이터 카탈로그 사용하기

Iceberg 테이블은 REST 카탈로그, AWS Glue Data Catalog, Unity Catalog와 같은 다양한 데이터 카탈로그와 함께 사용할 수도 있습니다.
카탈로그를 사용할 때는 대부분 DataLakeCatalog 데이터베이스 엔진을 사용하는 것이 좋습니다. 이 엔진은 ClickHouse를 카탈로그에 연결해 테이블을 검색할 수 있게 해줍니다. IcebergS3 테이블 엔진으로 개별 테이블을 수동 생성하는 대신 이 데이터베이스 엔진을 사용할 수 있습니다.
이러한 카탈로그를 사용하려면 IcebergS3 엔진으로 테이블을 생성하고 필요한 설정을 지정하십시오. 예를 들어, MinIO 스토리지와 함께 REST 카탈로그를 사용하는 경우:
CREATE TABLE `database_name.table_name`
ENGINE = IcebergS3(
  'http://minio:9000/warehouse-rest/table_name/',
  'minio_access_key',
  'minio_secret_key'
)
또는 S3와 함께 AWS Glue Data Catalog를 사용하세요:
CREATE TABLE `my_database.my_table`  
ENGINE = IcebergS3(
  's3://my-data-bucket/warehouse/my_database/my_table/',
  'aws_access_key',
  'aws_secret_key'
)

스키마 진화

현재 CH를 사용하면 시간이 지나며 스키마가 변경된 Iceberg 테이블을 읽을 수 있습니다. 현재는 컬럼이 추가되거나 삭제되고 순서가 바뀐 테이블 읽기를 지원합니다. 또한 값이 필수인 컬럼을 NULL을 허용하는 컬럼으로 변경할 수도 있습니다. 추가로, 단순 타입에 대해 허용된 타입 변환도 지원합니다. 구체적으로는 다음과 같습니다.  
  • int -> long
  • float -> double
  • decimal(P, S) -> decimal(P’, S) where P’ > P.
현재는 중첩 구조를 변경하거나 배열 및 맵 내부 요소의 타입을 변경할 수 없습니다.

파티션 프루닝

ClickHouse는 Iceberg 테이블의 SELECT 쿼리에서 파티션 프루닝을 지원하며, 관련 없는 데이터 파일을 건너뛰어 쿼리 성능을 최적화할 수 있습니다. 파티션 프루닝을 활성화하려면 use_iceberg_partition_pruning = 1로 설정하십시오. Iceberg 파티션 프루닝에 대한 자세한 내용은 https://iceberg.apache.org/spec/#partitioning 를 참조하십시오.

Time Travel

ClickHouse는 Iceberg 테이블에서 time travel을 지원하므로, 특정 타임스탬프 또는 스냅샷 ID를 기준으로 과거 데이터를 쿼리할 수 있습니다.

삭제된 행이 포함된 테이블 처리

현재는 position deletes가 있는 Iceberg 테이블만 지원합니다. 다음 삭제 방식은 지원하지 않습니다:

기본 사용법

 SELECT * FROM example_table ORDER BY 1 
 SETTINGS iceberg_timestamp_ms = 1714636800000
 SELECT * FROM example_table ORDER BY 1 
 SETTINGS iceberg_snapshot_id = 3547395809148285433
참고: 동일한 쿼리에서는 iceberg_timestamp_msiceberg_snapshot_id 매개변수를 동시에 지정할 수 없습니다.

중요하게 고려할 사항

  • 스냅샷은 일반적으로 다음과 같은 경우 생성됩니다:
  • 테이블에 새 데이터가 기록될 때
  • 어떤 형태의 데이터 컴팩션이 수행될 때
  • 스키마 변경은 일반적으로 스냅샷을 생성하지 않습니다 - 따라서 스키마 진화가 일어난 테이블에 time travel을 사용할 때 중요한 동작 특성이 발생합니다.

예시 시나리오

아직 CH에서 Iceberg 테이블에 쓰기를 지원하지 않으므로, 모든 시나리오는 Spark를 사용해 작성되었습니다.

시나리오 1: 새 스냅샷 없이 발생한 스키마 변경

다음 작업 순서를 살펴보겠습니다:
 -- 두 개의 컬럼으로 테이블 생성
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

- - 테이블에 데이터 삽입
  INSERT INTO spark_catalog.db.time_travel_example VALUES 
    (1, 'Mars')

  ts1 = now() // 의사 코드(pseudo code) 예시

- - 새 컬럼 추가를 위한 테이블 변경
  ALTER TABLE spark_catalog.db.time_travel_example ADD COLUMN (price double)
 
  ts2 = now()

- - 테이블에 데이터 삽입
  INSERT INTO spark_catalog.db.time_travel_example VALUES (2, 'Venus', 100)

   ts3 = now()

- - 각 타임스탬프 시점의 테이블 쿼리
  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts1;

+------------+------------+
|order_number|product_code|
+------------+------------+
|           1|        Mars|
+------------+------------+
  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts2;

+------------+------------+
|order_number|product_code|
+------------+------------+
|           1|        Mars|
+------------+------------+

  SELECT * FROM spark_catalog.db.time_travel_example TIMESTAMP AS OF ts3;

+------------+------------+-----+
|order_number|product_code|price|
+------------+------------+-----+
|           1|        Mars| NULL|
|           2|       Venus|100.0|
+------------+------------+-----+
서로 다른 타임스탬프의 쿼리 결과:
  • ts1 & ts2: 원래 있던 2개 컬럼만 표시됩니다
  • ts3: 3개 컬럼이 모두 표시되며, 첫 번째 행의 price는 NULL로 표시됩니다

시나리오 2: 과거 스키마와 현재 스키마의 차이

현재 시점에서 실행한 time travel 쿼리에서는 현재 테이블(table)과 다른 스키마(schema)가 표시될 수 있습니다:
-- 테이블 생성
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_2 (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2')

-- 테이블에 초기 데이터 삽입
  INSERT INTO spark_catalog.db.time_travel_example_2 VALUES (2, 'Venus');

-- 새 컬럼 추가를 위해 테이블 변경
  ALTER TABLE spark_catalog.db.time_travel_example_2 ADD COLUMN (price double);

  ts = now();

-- timestamp 구문을 사용하여 현재 시점 테이블 쿼리

  SELECT * FROM spark_catalog.db.time_travel_example_2 TIMESTAMP AS OF ts;

    +------------+------------+
    |order_number|product_code|
    +------------+------------+
    |           2|       Venus|
    +------------+------------+

-- 현재 시점 테이블 쿼리
  SELECT * FROM spark_catalog.db.time_travel_example_2;
    +------------+------------+-----+
    |order_number|product_code|price|
    +------------+------------+-----+
    |           2|       Venus| NULL|
    +------------+------------+-----+
이는 ALTER TABLE이 새 스냅샷을 생성하지 않기 때문입니다. 대신 현재 테이블에서는 Spark가 스냅샷이 아니라 최신 메타데이터 파일에서 schema_id 값을 가져옵니다.

시나리오 3: 과거 스키마와 현재 스키마의 차이점

둘째, time travel을 수행할 때는 테이블에 데이터가 한 번도 기록되기 전 시점의 상태를 가져올 수 없습니다:
-- 테이블 생성
  CREATE TABLE IF NOT EXISTS spark_catalog.db.time_travel_example_3 (
  order_number bigint, 
  product_code string
  ) 
  USING iceberg 
  OPTIONS ('format-version'='2');

  ts = now();

-- 특정 timestamp의 테이블 쿼리
  SELECT * FROM spark_catalog.db.time_travel_example_3 TIMESTAMP AS OF ts; -- 오류 발생: ts보다 오래된 snapshot을 찾을 수 없습니다.
ClickHouse에서는 동작 방식이 Spark와 일관됩니다. 즉, Spark의 Select 쿼리를 ClickHouse의 Select 쿼리로 바꿔 생각해도 동일하게 동작합니다.

메타데이터 파일 탐색

ClickHouse에서 iceberg 테이블 함수를 사용할 때 시스템은 Iceberg 테이블 구조를 설명하는 올바른 metadata.json 파일을 찾아야 합니다. 이 탐색 과정은 다음과 같이 이루어집니다:
  1. 직접 경로 지정: *iceberg_metadata_file_path를 설정하면 시스템은 이 값을 Iceberg 테이블 디렉터리 경로와 결합해 해당 정확한 경로를 사용합니다.
  • 이 설정이 지정되면 다른 모든 탐색 관련 설정은 무시됩니다.
  1. 테이블 UUID 일치: *iceberg_metadata_table_uuid가 지정되면 시스템은 다음과 같이 동작합니다. *metadata 디렉터리의 .metadata.json 파일만 확인합니다. *지정한 UUID와 일치하는 table-uuid 필드가 포함된 파일만 필터링합니다(대소문자 구분 없음).
  2. 기본 검색: *위 두 설정이 모두 지정되지 않으면 metadata 디렉터리의 모든 .metadata.json 파일이 후보가 됩니다.

가장 최근 파일 선택

위 규칙을 사용해 후보 파일을 식별한 후, 시스템은 그중에서 가장 최근 파일을 결정합니다:
  • iceberg_recent_metadata_file_by_last_updated_ms_field가 활성화된 경우:
  • last-updated-ms 값이 가장 큰 파일이 선택됩니다
  • 그렇지 않은 경우:
  • 버전 번호가 가장 높은 파일이 선택됩니다
  • (버전은 V.metadata.json 또는 V-uuid.metadata.json 형식의 파일명에서 V로 표시됩니다)
참고: 여기서 언급한 모든 설정은 테이블 함수 설정(전역 설정이나 쿼리 수준 설정이 아님)이며, 아래와 같이 지정해야 합니다:
SELECT * FROM iceberg('s3://bucket/path/to/iceberg_table', 
    SETTINGS iceberg_metadata_table_uuid = 'a90eed4c-f74b-4e5b-b630-096fb9d09021');
참고: 일반적으로는 Iceberg 카탈로그가 메타데이터 해석을 담당하지만, ClickHouse의 iceberg 테이블 함수는 S3에 저장된 파일을 Iceberg 테이블로 직접 해석합니다. 따라서 이러한 해석 규칙을 이해하는 것이 중요합니다.

메타데이터 캐시

Iceberg 테이블 엔진과 테이블 함수는 manifest 파일, manifest 목록, metadata json 정보를 저장하는 메타데이터 캐시를 지원합니다. 캐시는 메모리에 저장됩니다. 이 기능은 use_iceberg_metadata_files_cache 설정으로 제어되며, 기본적으로 활성화되어 있습니다.

별칭

이제 테이블 함수 icebergicebergS3의 별칭입니다.

가상 컬럼

  • _path — 파일의 경로. 유형: LowCardinality(String).
  • _file — 파일 이름. 유형: LowCardinality(String).
  • _size — 파일 크기(바이트). 유형: Nullable(UInt64). 파일 크기를 알 수 없으면 값은 NULL입니다.
  • _time — 파일이 마지막으로 수정된 시간. 유형: Nullable(DateTime). 시간을 알 수 없으면 값은 NULL입니다.
  • _etag — 파일의 etag. 유형: LowCardinality(String). etag를 알 수 없으면 값은 NULL입니다.

Iceberg 테이블에 쓰기

25.7 버전부터 ClickHouse는 사용자의 Iceberg 테이블을 수정할 수 있도록 지원합니다. 현재는 실험적 기능이므로 먼저 활성화해야 합니다:
SET allow_insert_into_iceberg = 1;

Iceberg 테이블 생성

직접 빈 Iceberg 테이블을 생성하려면 읽기와 동일한 명령을 사용하되, 스키마(schema)를 명시적으로 지정하십시오. 쓰기에서는 Parquet, Avro, ORC와 같은 Iceberg 사양의 모든 데이터 포맷을 지원합니다.

예시

CREATE TABLE iceberg_writes_example
(
    x Nullable(String),
    y Nullable(Int32)
)
ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/')
참고: 버전 힌트 파일을 생성하려면 iceberg_use_version_hint 설정을 활성화하십시오. metadata.json 파일을 압축하려면 iceberg_metadata_compression_method 설정에 코덱 이름을 지정하십시오.

INSERT

새 테이블을 생성한 후에는 일반적인 ClickHouse 구문을 사용해 데이터를 삽입할 수 있습니다.

예시

INSERT INTO iceberg_writes_example VALUES ('Pavel', 777), ('Ivanov', 993);

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Pavel
y: 777

Row 2:
──────
x: Ivanov
y: 993

DELETE

ClickHouse는 merge-on-read 포맷에서 불필요한 행을 삭제하는 기능도 지원합니다. 이 쿼리를 실행하면 포지션 삭제 파일이 포함된 새 스냅샷이 생성됩니다.

예시

ALTER TABLE iceberg_writes_example DELETE WHERE x != 'Ivanov';

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993

스키마 진화

ClickHouse에서는 단순 타입(튜플, 배열, 맵이 아닌 타입)의 컬럼을 추가, 삭제, 수정하거나 이름을 변경할 수 있습니다.

예시

ALTER TABLE iceberg_writes_example MODIFY COLUMN y Nullable(Int64);
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

ALTER TABLE iceberg_writes_example ADD COLUMN z Nullable(Int32);
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64),                                 ↴│
   │↳    `z` Nullable(Int32)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993
z: ᴺᵁᴸᴸ

ALTER TABLE iceberg_writes_example DROP COLUMN z;
SHOW CREATE TABLE iceberg_writes_example;
   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `y` Nullable(Int64)                                  ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993

ALTER TABLE iceberg_writes_example RENAME COLUMN y TO value;
SHOW CREATE TABLE iceberg_writes_example;

   ┌─statement─────────────────────────────────────────────────┐
1. │ CREATE TABLE default.iceberg_writes_example              ↴│
   │↳(                                                        ↴│
   │↳    `x` Nullable(String),                                ↴│
   │↳    `value` Nullable(Int64)                              ↴│
   │↳)                                                        ↴│
   │↳ENGINE = IcebergLocal('/home/scanhex12/iceberg_example/') │
   └───────────────────────────────────────────────────────────┘

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
value: 993

컴팩션

ClickHouse는 Iceberg 테이블의 컴팩션을 지원합니다. 현재는 메타데이터를 업데이트하면서 포지션 삭제 파일을 데이터 파일(data files)로 머지할 수 있습니다. 이전 스냅샷 ID와 타임스탬프는 변경되지 않으므로, 동일한 값으로 time-travel 기능을 계속 사용할 수 있습니다. 사용 방법:
SET allow_experimental_iceberg_compaction = 1

OPTIMIZE TABLE iceberg_writes_example;

SELECT *
FROM iceberg_writes_example
FORMAT VERTICAL;

Row 1:
──────
x: Ivanov
y: 993

스냅샷 만료

Iceberg 테이블은 각 INSERT, DELETE 또는 UPDATE 작업이 수행될 때마다 스냅샷이 누적됩니다. 시간이 지나면 스냅샷 수와 관련 데이터 파일 수가 크게 늘어날 수 있습니다. expire_snapshots 명령은 오래된 스냅샷을 제거하고, 유지되는 스냅샷 어느 것에서도 더 이상 참조되지 않는 데이터 파일을 정리합니다. 구문:
ALTER TABLE iceberg_table EXECUTE expire_snapshots(
    ['timestamp']
    [, expire_before = 'timestamp']
    [, retention_period = '3d']
    [, retain_last = 100]
    [, snapshot_ids = [1, 2, 3, 4]]
    [, dry_run = 1]
);
기본적으로 어떤 스냅샷을 유지할지는 보존 정책(테이블 속성 min-snapshots-to-keep, max-snapshot-age-ms 및 ref별 재정의)에 따라 결정됩니다. snapshot_ids를 지정하면 보존 정책을 우회하며, 나열된 스냅샷만 만료 대상으로 검토됩니다. 인수:
  • 'timestamp' (positional) 또는 expire_before = 'timestamp'서버의 시간대를 기준으로 해석되는 날짜 및 시간 문자열입니다(예: '2024-06-01 00:00:00'). 안전장치 역할을 합니다. 즉, timestamp-ms가 이 값과 같거나 이후인 스냅샷은 보존 정책에 따라 원래 만료될 대상이더라도 만료되지 않도록 보호됩니다. snapshot_ids와 함께 사용할 수도 있으며, 이 경우 나열된 스냅샷 중 타임스탬프와 같거나 그보다 최신인 항목은 만료되지 않습니다.
  • retention_period = '<duration>' — 이번 호출에만 테이블 수준의 history.expire.max-snapshot-age-ms를 재정의합니다. 이 기간보다 오래된 스냅샷(현재 시점을 기준으로 계산)이 만료 후보가 됩니다. 값은 하나 이상의 {number}{unit} 쌍을 이어 붙인 기간 문자열입니다. 지원되는 단위: y (365일), w (7일), d (24시간), h (60분), m (60초), s (1초), ms (1밀리초). 단위는 조합할 수 있으며, 예를 들어 '3d', '12h', '1d12h30m', '500ms'가 가능합니다.
  • retain_last = N — 이번 호출에만 테이블 수준의 history.expire.min-snapshots-to-keep를 재정의합니다. 기간과 무관하게 최소 N개의 스냅샷은 항상 유지됩니다.
  • snapshot_ids = [id1, id2, ...] — 나열된 스냅샷 ID만 정확히 만료합니다(현재 스냅샷, 브랜치 또는 태그가 참조하는 스냅샷은 제외). 이 모드는 보존 정책을 완전히 우회하며 retention_period 또는 retain_last와 함께 사용할 수 없습니다.
  • dry_run = 1 — 무엇이 만료될지를 계산하고, 새 메타데이터를 기록하거나 파일을 삭제하지 않은 상태로 메트릭을 반환합니다.
retention_periodretain_last테이블 수준의 기본 보존 설정만 재정의합니다. Iceberg 테이블 속성에 구성된 ref별(브랜치/태그) 보존 재정의(예: refs.<branch>.min-snapshots-to-keep)는 재정의되지 않으며, 항상 테이블 메타데이터에 지정된 대로 적용됩니다.
예시:
SET allow_insert_into_iceberg = 1;

-- 데이터를 삽입하여 스냅샷 생성
INSERT INTO iceberg_table VALUES (1);
INSERT INTO iceberg_table VALUES (2);
INSERT INTO iceberg_table VALUES (3);

-- 보존 정책만 사용하여 만료
ALTER TABLE iceberg_table EXECUTE expire_snapshots();

-- 안전 퓨즈 사용: 타임스탬프보다 최신인 스냅샷 보호 (위치 인수 구문)
ALTER TABLE iceberg_table EXECUTE expire_snapshots('2025-01-01 00:00:00');

-- 명명된 인수 형식으로 동일하게 실행
ALTER TABLE iceberg_table EXECUTE expire_snapshots(expire_before = '2025-01-01 00:00:00');

-- 단일 실행에 대해 보존 매개변수 재정의
ALTER TABLE iceberg_table EXECUTE expire_snapshots(retention_period = '3d', retain_last = 10);

-- 명시적 스냅샷 만료
ALTER TABLE iceberg_table EXECUTE expire_snapshots(snapshot_ids = [101, 102, 103]);

-- 드라이런 미리보기 (메타데이터 업데이트 없음, 파일 삭제 없음)
ALTER TABLE iceberg_table EXECUTE expire_snapshots(retention_period = '1d', dry_run = 1);
출력: 이 명령은 두 개의 컬럼(metric_name String, metric_value Int64)으로 구성된 테이블을 반환하며, 각 메트릭마다 하나의 행이 포함됩니다. 메트릭 이름은 Iceberg 사양을 따릅니다:
metric_name설명
deleted_data_files_count삭제된 데이터 파일 수
deleted_position_delete_files_count삭제된 포지션 삭제 파일 수
deleted_equality_delete_files_count삭제된 equality 삭제 파일 수
deleted_manifest_files_count삭제된 manifest 파일 수
deleted_manifest_lists_count삭제된 manifest 목록 파일 수
deleted_statistics_files_count삭제된 statistics 파일 수(현재는 항상 0)
dry_run드라이런 모드에서는 1, 일반 실행에서는 0
이 명령은 다음 단계를 수행합니다:
  1. 보존 정책(아래 참조)을 평가하여 유지해야 할 스냅샷을 결정합니다
  2. 타임스탬프 인수가 제공된 경우, 해당 타임스탬프 시점 이후를 포함한 모든 스냅샷도 추가로 보호합니다
  3. 정책에 따라 유지되지 않고 타임스탬프 퓨즈로도 보호되지 않는 스냅샷을 만료시킵니다
  4. 만료된 스냅샷에만 연결된 파일을 계산합니다
  5. 일반 모드: 만료된 스냅샷이 제외된 새 메타데이터를 생성합니다
  6. 일반 모드: 더 이상 도달할 수 없는 manifest 목록, manifest 파일, 데이터 파일을 물리적으로 삭제합니다
  7. dry_run = 1 모드: 5단계와 6단계를 건너뛰고 계산된 메트릭만 반환합니다

스냅샷 보존 정책

expire_snapshots 명령은 Iceberg 스냅샷 retention policy를 따릅니다. 보존 설정은 Iceberg 테이블 속성과 참조별 재정의 값으로 구성됩니다.
속성범위기본값설명
history.expire.min-snapshots-to-keep테이블iceberg_expire_default_min_snapshots_to_keep (기본값 1)각 브랜치의 조상 체인에서 유지할 최소 스냅샷 수
history.expire.max-snapshot-age-ms테이블iceberg_expire_default_max_snapshot_age_ms (기본값 432000000, 5일)브랜치에서 유지할 스냅샷의 최대 보존 기간(ms)
history.expire.max-ref-age-ms테이블iceberg_expire_default_max_ref_age_ms (기본값 )스냅샷 참조(브랜치 또는 태그) 자체를 제거하기 전까지 허용되는 최대 기간(ms)
각 스냅샷 참조(Iceberg 메타데이터의 refs)는 참조별 필드인 min-snapshots-to-keep, max-snapshot-age-ms, max-ref-age-ms로 이 값을 재정의할 수 있습니다. 보존 평가:
  • 각 브랜치(main 포함): 브랜치 헤드에서 시작해 조상 체인을 따라가며 검사합니다. 다음 조건 중 하나라도 만족하면 스냅샷이 유지됩니다.
    • 해당 스냅샷이 체인에서 앞의 min-snapshots-to-keep개 중 하나인 경우
    • 스냅샷의 경과 시간이 max-snapshot-age-ms 이내인 경우(즉, now - timestamp-ms <= max-snapshot-age-ms)
  • 태그의 경우: 태그가 가리키는 스냅샷은 유지되지만, 태그가 max-ref-age-ms를 초과하면 태그 참조가 제거됩니다
  • max-ref-age-ms를 초과한 main이 아닌 참조는 완전히 제거됩니다(main 브랜치는 제거되지 않음)
  • 존재하지 않는 스냅샷을 가리키는 고아 참조는 경고와 함께 제거됩니다
  • 현재 스냅샷은 항상 유지되며, 보존 설정과 관계없습니다
필요한 권한: ALTER TABLE EXECUTE 권한이 필요합니다. 이 권한은 ClickHouse 접근 제어 계층 구조에서 ALTER TABLE의 하위 권한입니다. 이 권한만 개별적으로 부여하거나 상위 권한을 통해 부여할 수 있습니다.
-- EXECUTE 권한만 부여
GRANT ALTER TABLE EXECUTE ON my_iceberg_table TO my_user;

-- 또는 모든 ALTER TABLE 권한 부여 (ALTER TABLE EXECUTE 포함)
GRANT ALTER TABLE ON my_iceberg_table TO my_user;
  • Iceberg 형식 버전 2 테이블만 지원됩니다(v1 스냅샷은 정리 작업에 필요한 파일을 안전하게 식별하는 데 필요한 manifest-list를 보장하지 않음)
  • 지정된 타임스탬프보다 오래된 경우에도 현재 스냅샷은 항상 유지됩니다
  • allow_insert_into_iceberg setting이 활성화되어 있어야 합니다
  • allow_experimental_expire_snapshots setting이 활성화되어 있어야 합니다
  • ClickHouse가 메타데이터를 업데이트할 때는 카탈로그 자체의 권한 부여(REST 카탈로그 인증, AWS Glue IAM 등)가 별도로 적용됩니다

고아 파일 제거

고아 파일은 Iceberg 테이블 메타데이터의 어떤 스냅샷에서도 참조되지 않는 스토리지 내 파일입니다. 이러한 파일은 쓰기 실패, 컴팩션 이후의 불완전한 정리, 작업 중단으로 인해 누적되며 스토리지 사용량이 제한 없이 증가하는 원인이 됩니다. remove_orphan_files 명령은 이러한 고아 파일을 식별해 제거합니다. 구문:
-- 위치 기반 형식: 이름 없는 단일 older_than 인수
ALTER TABLE iceberg_table EXECUTE remove_orphan_files('timestamp')

-- 명명된 형식
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    older_than = 'timestamp',
    location = 'path',
    dry_run = 0|1
)

-- 인수 없음: 모든 기본값 사용 (older_than = 3일 전)
ALTER TABLE iceberg_table EXECUTE remove_orphan_files()
매개변수:
매개변수유형기본값설명
older_thanString (timestamp)3일 전 (iceberg_orphan_files_older_than_seconds로 설정 가능)마지막 수정 시간이 이 timestamp보다 이전인 파일만 고아 파일 후보로 간주합니다. 진행 중인 쓰기 작업의 파일이 삭제되지 않도록 하는 안전장치입니다.
locationString테이블 위치테이블 위치 아래의 특정 하위 디렉터리만 스캔하도록 제한합니다(예: 'data/' 또는 'metadata/').
dry_runUInt6401이면 고아 파일을 식별하고 실제로는 아무것도 삭제하지 않은 상태로 결과 요약만 반환합니다.
예시:
-- 특정 타임스탬프보다 오래된 고아 파일 제거
ALTER TABLE iceberg_table EXECUTE remove_orphan_files('2026-03-01 00:00:00');

-- 드라이 런: 삭제될 파일 미리 보기
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(dry_run = 1);

-- 데이터 디렉터리만 스캔
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    older_than = '2026-03-01 00:00:00',
    location = 'data/'
);

-- 위치 인수 older_than과 명명된 인수 조합
ALTER TABLE iceberg_table EXECUTE remove_orphan_files(
    '2026-03-01 00:00:00',
    dry_run = 1
);
출력: 이 명령은 카테고리별 삭제된 파일 수(또는 dry&#95;run 모드에서 삭제 예정인 파일 수)를 보여주는 metric_namemetric_value 컬럼이 있는 테이블을 반환합니다. 파일 카테고리는 파일 이름 규칙을 바탕으로 한 최선의 휴리스틱으로 분류되며, 특정 패턴과 일치하지 않는 파일은 기본적으로 deleted_data_files_count로 분류됩니다:
metric_namemetric_value
deleted_data_files_count5
deleted_position_delete_files_count2
deleted_equality_delete_files_count0
deleted_manifest_files_count3
deleted_manifest_lists_count1
deleted_metadata_files_count0
deleted_statistics_files_count0
skipped_missing_metadata_count0
failed_deletions_count0
설정:
SettingTypeDefaultDescription
allow_iceberg_remove_orphan_filesBoolfalse기능을 활성화하기 위한 게이트 설정입니다(실험적).
iceberg_orphan_files_older_than_secondsUInt64259200 (3 days)인수가 생략된 경우 적용되는 기본 older_than 임계값(초)입니다.
  • Iceberg 형식 버전 2 이상이 필요합니다. 버전 1 테이블은 스냅샷에 manifest-list 포인터가 없어 도달 가능한 파일 집합을 안전하게 판별할 수 없으므로 거부됩니다. v1 테이블에서 이 명령을 실행하면 BAD_ARGUMENTS 오류가 반환됩니다.
  • allow_insert_into_icebergallow_iceberg_remove_orphan_files 설정이 모두 활성화되어 있어야 합니다
  • 만료된 스냅샷에서만 참조되는 파일이 먼저 정리되도록 remove_orphan_files 전에 expire_snapshots를 실행하는 것이 좋습니다
  • 삭제 전에 고아 파일을 미리 확인하려면 dry_run = 1을 사용하세요
  • older_than 임계값은 진행 중인 쓰기 작업의 파일이 삭제되는 것을 방지합니다 — 기본 3일 임계값은 충분한 안전 여유를 제공합니다

관련 항목

마지막 수정일 2026년 6월 10일