Blog
trinoicebergmaintenancecompactionlakehousedata-platform

Trino 로 Iceberg 테이블 유지보수 — OPTIMIZE, 스냅샷 만료, 고아 파일 제거

Iceberg 테이블은 운영하면서 점점 느려집니다. 작은 파일 누적, 스냅샷 폭증, 고아 파일이 원인입니다. Trino 의 ALTER TABLE ... EXECUTE 프로시저로 컴팩션·스냅샷 만료·고아 파일 정리를 자동화하는 법과 메타데이터 테이블로 상태를 진단하는 법을 정리합니다.

Data Dynamics2026년 6월 5일11 min read

Iceberg 테이블은 만들 때는 빠르지만, 운영하면서 서서히 느려집니다. 스트리밍 적재나 잦은 INSERT/MERGE 가 쌓이면 작은 파일이 폭증하고, 매 쓰기마다 새 스냅샷이 생기며, 만료된 데이터 파일이 스토리지에 고아로 남습니다. 이걸 방치하면 쿼리 플래닝이 수십 초로 늘고 스토리지 비용이 새어 나갑니다.

다행히 Trino 는 이 유지보수 작업을 SQL 한 줄로 실행할 수 있는 프로시저를 제공합니다. 이 글은 무엇이 테이블을 느리게 만드는지, 그리고 OPTIMIZE / expire_snapshots / remove_orphan_files 로 어떻게 정리하는지를 진단부터 자동화까지 정리합니다.

1. Iceberg 테이블이 느려지는 세 가지 원인

①  작은 파일(Small Files)   → 파일마다 메타·footer I/O, 플래닝 폭증
②  스냅샷 누적(Snapshots)   → metadata 파일 비대, time travel 이력 과다
③  고아 파일(Orphan Files)  → 더 이상 참조 안 되는 데이터가 스토리지에 잔존
원인증상해결 프로시저
작은 파일데이터는 적은데 쿼리 플래닝이 느림EXECUTE optimize
스냅샷 누적metadata.json 비대, 플래닝 지연EXECUTE expire_snapshots
고아 파일스토리지 용량이 실제 데이터보다 큼EXECUTE remove_orphan_files

2. 먼저 진단 — 메타데이터 테이블

Trino 는 Iceberg 테이블의 내부 상태를 "테이블$메타테이블" 형태로 조회하게 해줍니다. 정리 전에 현황을 파악하세요.

-- 데이터 파일 수와 총 용량 (작은 파일 진단)
SELECT count(*) AS file_count,
       sum(file_size_in_bytes) / (1024*1024*1024) AS total_gb,
       avg(file_size_in_bytes) / (1024*1024) AS avg_file_mb
FROM iceberg.analytics."events$files";
 
-- 스냅샷 개수와 이력 (스냅샷 누적 진단)
SELECT count(*) AS snapshot_count,
       min(committed_at) AS oldest,
       max(committed_at) AS newest
FROM iceberg.analytics."events$snapshots";
 
-- 파티션별 파일 분포 (특정 파티션만 작은 파일이 몰렸는지)
SELECT partition, file_count, total_size
FROM iceberg.analytics."events$partitions"
ORDER BY file_count DESC
LIMIT 20;

주요 메타데이터 테이블:

테이블내용
$files데이터 파일 목록·크기·통계
$snapshots스냅샷 이력·커밋 시각
$partitions파티션별 파일 수·행 수·크기
$manifestsmanifest 파일 목록
$history테이블 상태 변경 이력

진단 기준: avg_file_mb 가 수 MB 이하로 낮고 file_count 가 수만수십만이면 작은 파일 문제, snapshot_count 가 수백수천이면 스냅샷 누적 문제입니다.

3. OPTIMIZE — 작은 파일 컴팩션

작은 파일들을 모아 적정 크기(기본 목표 약 512MB)의 큰 파일로 병합합니다.

-- 테이블 전체 컴팩션
ALTER TABLE iceberg.analytics.events EXECUTE optimize;
 
-- 특정 파티션만 (권장: 최근 적재 구간만)
ALTER TABLE iceberg.analytics.events EXECUTE optimize
  WHERE event_time >= TIMESTAMP '2026-06-01 00:00:00 UTC'
    AND event_time <  TIMESTAMP '2026-06-05 00:00:00 UTC';
 
-- 특정 크기 미만 파일만 대상으로 (file_size_threshold)
ALTER TABLE iceberg.analytics.events EXECUTE optimize(file_size_threshold => '128MB');

핵심 포인트:

  • WHERE 로 범위를 좁히세요. 전체 컴팩션은 비싸고 오래 걸립니다. 스트리밍 적재라면 "어제~오늘" 파티션만 매일 컴팩션하는 식이 효율적입니다.
  • file_size_threshold 보다 작은 파일만 대상으로 잡으면, 이미 큰 파일은 건드리지 않아 비용이 절감됩니다.
  • 컴팩션은 새 스냅샷을 생성합니다. 이전 작은 파일들은 즉시 삭제되지 않고 고아 후보가 되므로, 컴팩션 후 스냅샷 만료 + 고아 파일 제거를 이어서 하는 것이 정석입니다.

정렬을 곁들인 컴팩션

테이블에 sorted_by 가 설정돼 있으면 OPTIMIZE 가 데이터를 정렬해 다시 씁니다. 정렬은 Parquet min/max 통계 효과를 키워 프루닝을 개선합니다.

ALTER TABLE iceberg.analytics.events SET PROPERTIES sorted_by = ARRAY['user_id'];
ALTER TABLE iceberg.analytics.events EXECUTE optimize;

4. expire_snapshots — 스냅샷 만료

Iceberg 는 매 쓰기마다 스냅샷을 남깁니다(time travel·롤백용). 오래 쌓이면 metadata 파일이 커지고, 만료 전까지는 옛 데이터 파일도 삭제되지 않습니다.

-- 7일보다 오래된 스냅샷 만료
ALTER TABLE iceberg.analytics.events EXECUTE expire_snapshots(retention_threshold => '7d');

동작:

  • retention_threshold 보다 오래된 스냅샷을 제거하고, 그 스냅샷에서만 참조되던 데이터 파일을 실제로 삭제합니다.
  • 즉 expire_snapshots 가 OPTIMIZE 가 남긴 옛 작은 파일들을 실제로 회수하는 단계입니다.
  • 너무 짧게 잡으면 time travel·롤백 여력이 사라지므로, 운영 정책(보통 3~14일)에 맞추세요.
-- time travel: 만료 전이라면 과거 시점 조회 가능
SELECT * FROM iceberg.analytics.events
FOR TIMESTAMP AS OF TIMESTAMP '2026-06-03 00:00:00 UTC';

주의: retention_threshold 는 보통 클러스터 기본 최소값(예: 7일) 이하로는 낮추지 못하도록 안전장치가 걸려 있습니다. 더 짧게 강제하려면 테이블/카탈로그 설정을 조정해야 하며, 데이터 보호 관점에서 권장하지 않습니다.

5. remove_orphan_files — 고아 파일 제거

스토리지에는 있지만 어떤 스냅샷도 참조하지 않는 파일(고아)을 삭제합니다. 비정상 종료된 쓰기, 실패한 커밋, 외부 도구의 잔여물 등이 원인입니다.

ALTER TABLE iceberg.analytics.events EXECUTE remove_orphan_files(retention_threshold => '7d');
  • retention_threshold 보다 오래된 고아 파일만 제거합니다. 이 값을 너무 짧게 잡으면, 지금 막 커밋 중인(아직 메타데이터에 반영 전인) 파일을 고아로 오인해 삭제할 수 있으므로 반드시 넉넉히(기본 7일 권장) 둡니다.
  • 동시에 쓰기 작업이 진행 중일 때 너무 공격적으로 돌리지 마세요. 쓰기가 한가한 시간대에 실행하는 것이 안전합니다.

6. 권장 유지보수 순서

세 작업은 순서가 중요합니다.

① OPTIMIZE              작은 파일 → 큰 파일 (새 스냅샷 생성, 옛 파일은 고아 후보화)

② expire_snapshots      오래된 스냅샷 제거 → 더 이상 참조 안 되는 데이터 파일 실제 삭제

③ remove_orphan_files   메타데이터가 모르는 잔여 파일까지 회수
-- 일일 유지보수 묶음 (최근 파티션 컴팩션 + 정리)
ALTER TABLE iceberg.analytics.events EXECUTE optimize
  WHERE event_time >= current_timestamp - INTERVAL '2' DAY;
ALTER TABLE iceberg.analytics.events EXECUTE expire_snapshots(retention_threshold => '7d');
ALTER TABLE iceberg.analytics.events EXECUTE remove_orphan_files(retention_threshold => '7d');

7. 자동화 — 무엇을 얼마나 자주

워크로드별 권장 주기입니다.

작업스트리밍/잦은 적재일배치 적재거의 정적
OPTIMIZE매일(최근 파티션)매일/주간월간
expire_snapshots매일주간월간
remove_orphan_files주간주간월간

자동화 방법:

  • 스케줄러(Airflow/cron) 에서 위 SQL 묶음을 테이블별로 실행.
  • 컴팩션은 별도의 유지보수용 Resource Group(낮은 동시성)에 배정해, 분석 쿼리 자원을 침범하지 않게 합니다.
  • 큰 테이블은 한 번에 전체를 돌리지 말고 파티션 범위를 나눠 점진적으로.

8. 흔한 함정

함정결과회피
OPTIMIZE 만 하고 스냅샷 만료 안 함옛 작은 파일이 안 지워져 스토리지 그대로항상 expire_snapshots 동반
retention_threshold 너무 짧게진행 중 파일 오삭제 / time travel 상실7일 이상 권장
전체 OPTIMIZE 를 매일비용·시간 폭발WHERE 로 최근 파티션만
쓰기 피크에 유지보수커밋 충돌, 자원 경합한가한 시간대 + 전용 Resource Group
remove_orphan_files 를 분석 클러스터에서 공격적으로I/O 부하주간·저부하 시간

9. 정리

프로시저해결핵심 옵션
EXECUTE optimize작은 파일 병합(+정렬)WHERE, file_size_threshold
EXECUTE expire_snapshots스냅샷·옛 파일 정리retention_threshold
EXECUTE remove_orphan_files미참조 잔여 파일 회수retention_threshold

Iceberg 테이블 유지보수의 핵심은 세 가지를 순서대로, 정기적으로, 범위를 좁혀서 돌리는 것입니다. $files·$snapshots 메타데이터 테이블로 현황을 먼저 진단하고, 스트리밍 테이블은 최근 파티션 컴팩션을 매일, 스냅샷·고아 정리를 주기적으로 자동화하세요. 이 루틴만 갖춰도 "시간이 지날수록 느려지는" Iceberg 의 고질병을 구조적으로 막을 수 있습니다.


이 글은 Trino 440번대 + Iceberg spec v2 기준으로 작성되었습니다. Lakehouse 테이블 유지보수 자동화나 성능 저하 진단이 필요하시면 언제든 문의해 주세요.

— Data Dynamics 엔지니어링 팀