Iceberg 확장
Iceberg 확장
iceberg 확장은 Apache Iceberg 오픈 테이블 포맷을 지원해요. DuckDB에서 Iceberg를 다루는 두 가지 방식, 개별 테이블 직접 읽기와 카탈로그 관리 테이블 방식을 함께 알아볼까요?
출처: 문서
본문
iceberg 확장은 Apache Iceberg 오픈 테이블 포맷을 지원해요. DuckDB에서 Iceberg로 작업하는 두 가지 방법이 있어요:
- 개별 테이블 은 테이블의 메타데이터를 가리켜서 저장소에서 직접 읽혀요. 카탈로그가 필요 없고 읽기 전용이에요.
- 카탈로그 관리 테이블 은 Iceberg REST 카탈로그를 연결해서 접근해요. 쓰기를 포함한 전체 기능 집합을 사용할 수 있어요.
이 페이지는 둘 다의 기본을 다뤄요. 다음도 참고하세요:
- [Writing to Iceberg]({% link docs/current/core_extensions/iceberg/writing_to_iceberg.md %})는 지원되는 쓰기 연산, 파티셔닝, 스키마 진화를 설명해요.
- [Iceberg Functions]({% link docs/current/core_extensions/iceberg/iceberg_functions.md %})는 확장이 제공하는 함수를 문서화해요.
- [Iceberg Options]({% link docs/current/core_extensions/iceberg/iceberg_options.md %})는 스캔 파라미터,
ATTACH옵션, secret 옵션, 설정을 문서화해요. - [Catalogs]({% link docs/current/core_extensions/iceberg/catalogs.md %})는 특정 카탈로그에 대한 지침과 함께 Iceberg REST 카탈로그를 연결하는 방법을 설명해요.
- [Troubleshooting]({% link docs/current/core_extensions/iceberg/troubleshooting.md %})은 흔한 문제와 해결책을 나열해요.
설치와 로드 (Installing and Loading)
iceberg 확장은 첫 사용 시 자동으로 설치되고 로드돼요.
직접 설치하고 로드하려면 다음을 실행하세요:
INSTALL iceberg;
LOAD iceberg;
확장 업데이트 (Updating the Extension)
iceberg 확장은 DuckDB 릴리스 사이에도 업데이트를 자주 받아요.
최신 버전인지 확인하려면 [확장을 업데이트]({% link docs/current/sql/statements/update_extensions.md %})하세요:
UPDATE EXTENSIONS;
Iceberg 테이블 읽기 (Reading Iceberg Tables)
개별 Iceberg 테이블은 카탈로그에 연결하지 않고 iceberg_scan 함수로 저장소에서 직접 읽을 수 있어요. 예시를 테스트하려면 [iceberg_data.zip]({% link data/iceberg_data.zip %}) 파일을 다운로드하고 압축을 풀어요.
개별 테이블 쿼리 (Querying Individual Tables)
[iceberg_scan 함수]({% link docs/current/core_extensions/iceberg/iceberg_functions.md %}#iceberg_scan)로 경로에서 Iceberg 테이블을 읽어요:
SELECT count(*)
FROM iceberg_scan('data/iceberg/lineitem_iceberg', allow_moved_paths = true);
| count_star() |
|---|
| 51793 |
allow_moved_paths옵션은 일부 경로 해석이 수행되도록 보장해서, 이동된 Iceberg 테이블을 스캔할 수 있게 해줘요.
쿼리에서 현재 매니페스트를 직접 지정할 수도 있어요. 이는 쿼리 전에 카탈로그에서 해석될 수 있어요. 이 예시에서 매니페스트 버전은 UUID예요.
이렇게 하려면 data/iceberg 디렉토리로 이동해서 다음을 실행하세요:
SELECT count(*)
FROM iceberg_scan('lineitem_iceberg/metadata/v1.metadata.json');
| count_star() |
|---|
| 60175 |
iceberg_scan이 받는 파라미터의 전체 목록은 [Iceberg Options]({% link docs/current/core_extensions/iceberg/iceberg_options.md %}#scan-options) 페이지를 참고하세요.
객체 스토어에서 읽기 (Reading from Object Stores)
iceberg 확장은 [httpfs 확장]({% link docs/current/core_extensions/httpfs/overview.md %}) 또는 [azure 확장]({% link docs/current/core_extensions/azure.md %})과 함께 동작해서 S3나 Azure Blob Storage 같은 객체 스토어의 Iceberg 테이블에 접근해요.
SELECT count(*)
FROM iceberg_scan('s3://bucketname/lineitem_iceberg/metadata/v1.metadata.json');
Iceberg 메타데이터 접근 (Accessing Iceberg Metadata)
Iceberg 메타데이터에 접근하려면 iceberg_metadata 함수를 사용할 수 있어요:
SELECT *
FROM iceberg_metadata('data/iceberg/lineitem_iceberg', allow_moved_paths = true);
| manifest_path | manifest_sequence_number | manifest_content | status | content | file_path | file_format | record_count |
|---|---|---|---|---|---|---|---|
| lineitem_iceberg/metadata/10eaca8a-1e1c-421e-ad6d-b232e5ee23d3-m1.avro | 2 | DATA | ADDED | EXISTING | lineitem_iceberg/data/00041-414-f3c73457-bbd6-4b92-9c15-17b241171b16-00001.parquet | PARQUET | 51793 |
| lineitem_iceberg/metadata/10eaca8a-1e1c-421e-ad6d-b232e5ee23d3-m0.avro | 2 | DATA | DELETED | EXISTING | lineitem_iceberg/data/00000-411-0792dcfe-4e25-4ca3-8ada-175286069a47-00001.parquet | PARQUET | 60175 |
스냅샷 시각화 (Visualizing Snapshots)
Iceberg 테이블의 스냅샷을 시각화하려면 iceberg_snapshots 함수를 사용하세요:
SELECT *
FROM iceberg_snapshots('data/iceberg/lineitem_iceberg');
| sequence_number | snapshot_id | timestamp_ms | manifest_list |
|---|---|---|---|
| 1 | 3776207205136740581 | 2023-02-15 15:07:54.504 | lineitem_iceberg/metadata/snap-3776207205136740581-1-cf3d0be5-cf70-453d-ad8f-48fdc412e608.avro |
| 2 | 7635660646343998149 | 2023-02-15 15:08:14.73 | lineitem_iceberg/metadata/snap-7635660646343998149-1-10eaca8a-1e1c-421e-ad6d-b232e5ee23d3.avro |
iceberg_snapshots는allow_moved_paths,snapshot_from_id,snapshot_from_timestamp를 파라미터로 받지 않아요.
메타데이터 버전 선택 (Selecting Metadata Versions)
기본적으로 iceberg 확장은 사용할 올바른 메타데이터 버전을 식별하기 위해 version-hint.text 파일을 찾아요. 이것은 iceberg 확장의 함수에 version 파라미터로 버전 번호를 명시적으로 제공해서 재정의할 수 있어요:
SELECT *
FROM iceberg_snapshots(
'data/iceberg/lineitem_iceberg',
version = '1'
);
기본적으로 iceberg 함수는 v{version}.metadata.json과 {version}.metadata.json 파일을 모두 찾거나, metadata_compression_codec = 'gzip'이 지정되면 v{version}.gz.metadata.json과 {version}.gz.metadata.json을 찾아요.
다른 압축 코덱은 지원되지 않아요.
version 파라미터로 어떤 텍스트 파일이 제공되면, 그것이 열려서 버전 힌트 파일로 취급돼요:
SELECT *
FROM iceberg_snapshots(
'data/iceberg/lineitem_iceberg',
version = 'version-hint.txt'
);
iceberg 확장은 이 파일을 열고 파일의 전체 내용을 제공된 버전 번호로 사용해요.
version-hint.txt 파일의 전체 내용은 인코딩, 이스케이프, 트리밍 없이 리터럴 버전 이름으로 취급된다는 점을 주의하세요. 여기에는 아래 설명된 로직에서 파일 이름으로 형식화되어 명시적으로 전달될 어떤 공백이나 안전하지 않은 문자도 포함돼요.
대체 메타데이터 명명 규칙 작업 (Working with Alternative Metadata Naming Conventions)
iceberg 확장은 version_name_format 파라미터를 통해 쉼표로 구분된 형식 문자열 목록으로 다른 메타데이터 명명 규칙을 처리할 수 있어요. 각 형식 문자열은 두 개의 %s 파라미터를 포함해야 해요. 첫 번째는 메타데이터 파일 이름에서 버전 번호의 위치이고, 두 번째는 metadata_compression_codec이 지정한 파일 확장자의 위치예요. 위에서 설명한 동작은 기본값 "v%s%s.metadata.gz,%s%smetadata.gz가 제공해요.
대체 이름의 메타데이터 파일(예: rev-2.metadata.json.gz)이 있다면, 다음 문장으로 테이블을 읽을 수 있어요:
SELECT *
FROM iceberg_snapshots(
'data/iceberg/alternative_metadata_gz_naming',
version = '2',
version_name_format = 'rev-%s.metadata.json%s',
metadata_compression_codec = 'gzip'
);
메타데이터 버전 "추측하기" ("Guessing" Metadata Versions)
기본적으로 iceberg 확장이 테이블을 읽으려면 테이블 버전 번호나 version-hint.text가 제공되어야 해요. 이것은 보통 외부 데이터 카탈로그가 제공해요. 둘 다 없을 경우 iceberg 확장은 version 파라미터로 ?를 전달해서 최신 버전을 추측하려 시도할 수 있어요:
SELECT count(*)
FROM iceberg_scan(
'data/iceberg/lineitem_iceberg_no_hint',
version = '?',
allow_moved_paths = true
);
"최신" 버전은 파일 이름을 정렬할 때 사전식으로 가장 큰 파일 이름으로 간주돼요. 콜레이션은 고려되지 않아요. 이 동작은 ACID 제약을 위반할 수 있어 기본적으로 활성화되지 않아요. unsafe_enable_version_guessing을 true로 설정해서 활성화할 수 있어요. 이것이 설정되면 iceberg 함수는 실패하기 전에 기본적으로 최신 버전을 추측하려 시도해요.
SET unsafe_enable_version_guessing = true;
SELECT count(*)
FROM iceberg_scan(
'data/iceberg/lineitem_iceberg_no_hint',
allow_moved_paths = true
);
시간 여행 (Time Travel)
테이블의 과거 스냅샷을 읽으려면 snapshot_from_id 또는 snapshot_from_timestamp 중 하나를 전달하세요 (둘은 상호 배타적이에요). iceberg_snapshots로 사용 가능한 스냅샷을 나열하세요:
-- id로 특정 스냅샷 읽기
SELECT count(*)
FROM iceberg_scan('data/iceberg/lineitem_iceberg', snapshot_from_id = 7635660646343998149);
-- 주어진 시간에 현재였던 스냅샷 읽기
SELECT count(*)
FROM iceberg_scan('data/iceberg/lineitem_iceberg', snapshot_from_timestamp = TIMESTAMP '2023-02-15 15:08:00');
직접 읽기의 제한 사항 (Limitations of Direct Reads)
- 버전 추측이 활성화되지 않는 한, 테이블을 읽으려면 버전 힌트나 명시적
version이 필요해요. gzip압축 메타데이터만 지원돼요 (metadata_compression_codec = 'gzip'으로).
카탈로그 관리 테이블 (Catalog Managed Tables)
전체 읽기 및 쓰기 접근 — 그리고 Iceberg의 카탈로그 기능 사용 — 을 위해 Iceberg REST 카탈로그를 연결하세요. 대부분의 카탈로그는 OAuth2로 인증해요. 자격 증명을 [secret]({% link docs/current/configuration/secrets_manager.md %})에 저장하고 ATTACH ... (TYPE iceberg, ...)으로 카탈로그를 연결하세요:
CREATE SECRET iceberg_secret (
TYPE iceberg,
CLIENT_ID '⟨admin⟩',
CLIENT_SECRET '⟨password⟩',
OAUTH2_SERVER_URI '⟨https://catalog.example.com/v1/oauth/tokens⟩'
);
ATTACH '⟨warehouse⟩' AS my_catalog (
TYPE iceberg,
SECRET iceberg_secret,
ENDPOINT '⟨https://catalog.example.com⟩'
);
연결되면 카탈로그는 다른 DuckDB 데이터베이스처럼 동작해요: 테이블을 ⟨catalog⟩.⟨schema⟩.⟨table⟩로 참조하고 일반 SQL로 쿼리하거나 수정하세요.
SHOW ALL TABLES;
SELECT count(*) FROM my_catalog.default.events;
INSERT INTO my_catalog.default.events VALUES (1, 'click', now());
[메타데이터 함수]({% link docs/current/core_extensions/iceberg/reference.md %}#read-and-metadata-functions)는 정규화된 이름이 전달되면 카탈로그 테이블에서도 동작해요, 예: iceberg_snapshots(my_catalog.default.events).
- 파티셔닝,
UPDATE,DELETE,MERGE INTO,ALTER TABLE, 테이블 속성을 포함한 전체 쓰기 연산 집합은 [Writing to Iceberg]({% link docs/current/core_extensions/iceberg/writing.md %})를 참고하세요. - 카탈로그별 설정과
ATTACH옵션 및 secret 파라미터의 전체 목록은 [Iceberg REST Catalogs]({% link docs/current/core_extensions/iceberg/iceberg_rest_catalogs.md %})를 참고하세요.
시간 여행 (Time Travel)
연결된 카탈로그에서는 AT 절로 테이블에서 직접 시간 여행을 할 수 있어요:
-- snapshot id 사용
SELECT * FROM my_catalog.default.events AT (VERSION => ⟨snapshot_id⟩);
-- timestamp 사용
SELECT * FROM my_catalog.default.events AT (TIMESTAMP => TIMESTAMP '2025-09-22 12:32:43.217');
DuckLake와의 상호운용 (Interoperability with DuckLake)
iceberg_to_ducklake 함수는 연결된 Iceberg 카탈로그의 메타데이터 전용 사본을 [DuckLake]({% link docs/current/core_extensions/ducklake.md %}) 카탈로그로 만들어서, Iceberg 테이블을 DuckLake 테이블처럼 쿼리할 수 있게 해줘요:
-- my_catalog로 연결된 Iceberg 카탈로그와 함께
ATTACH 'ducklake:my_ducklake.ducklake' AS my_ducklake;
CALL iceberg_to_ducklake('my_catalog', 'my_ducklake');
-- 특정 테이블 건너뛰기
CALL iceberg_to_ducklake('my_catalog', 'my_ducklake', skip_tables := ['table_to_skip']);