Blog
trinoicebergmaintenancecompactionlakehousedata-platform

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

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

Data Dynamics2026年6月5日17 min read
This post is not yet translated. The original Korean version is shown below.

상용 서비스를 운영하다 보면 어느 순간 "분명히 데이터가 늘지도 않았는데 쿼리가 왜 이렇게 느리지?"라는 상황을 만나게 되죠. Iceberg 테이블도 똑같습니다. 처음 만들었을 때는 쌩쌩하지만, 운영하면서 서서히 내부가 지저분해집니다. 스트리밍 적재나 잦은 INSERT/MERGE 가 쌓이면 작은 파일이 폭증하고, 매 쓰기마다 새 스냅샷이 생기며, 만료된 데이터 파일이 스토리지에 고아로 남습니다. 이걸 방치하면 쿼리 플래닝이 수십 초로 늘고 스토리지 비용이 새어 나갑니다.

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

이 글에서 배우는 것

  • Iceberg 테이블 성능을 갉아먹는 세 가지 원인(작은 파일·스냅샷 누적·고아 파일)
  • 메타데이터 테이블($files, $snapshots, $partitions)로 현황을 진단하는 방법
  • EXECUTE optimize로 작은 파일을 병합하고 정렬까지 적용하는 방법
  • expire_snapshotsremove_orphan_files로 스토리지를 실제로 회수하는 방법
  • 세 작업을 올바른 순서로 자동화하는 권장 패턴

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

Iceberg 가 느려지는 이유는 세 가지로 깔끔하게 정리됩니다. 각각이 어떤 증상을 만들고, 어떤 프로시저로 해결하는지 먼저 큰 그림을 잡아 봅시다.

Loading diagram…
원인증상해결 프로시저
작은 파일데이터는 적은데 쿼리 플래닝이 느림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 — 작은 파일 컴팩션

한 문장으로: 작은 파일 수백 개를 적정 크기의 큰 파일 몇 개로 합쳐 I/O 와 플래닝 비용을 한 번에 줄이는 작업입니다.

여러분의 테이블에 작은 파일이 수만 개라는 진단 결과가 나왔다면 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 — 스냅샷 만료

OPTIMIZE 로 파일을 병합했다고 해서 디스크 공간이 바로 줄어드는 건 아닙니다. 옛 작은 파일들은 아직 스냅샷에 참조된 채 남아 있거든요. 이 단계가 그 스냅샷들을 실제로 지워 공간을 돌려받는 과정입니다. 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 — 고아 파일 제거

스냅샷까지 정리했는데도 스토리지 용량이 예상보다 크다면 고아 파일이 범인일 수 있습니다. 비정상 종료된 쓰기, 실패한 커밋, 외부 도구의 잔여물 같은 것들이 스냅샷에는 등록되지 않은 채 스토리지에만 남아 있는 경우입니다. 이걸 고아(orphan) 파일이라 부르는데, 이 프로시저가 그것들을 깨끗하게 쓸어 담습니다.

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

6. 권장 유지보수 순서

세 작업을 각각 이해했다면 이제 순서가 중요합니다. 순서를 바꾸면 기대한 효과가 나지 않거나 데이터를 잘못 지울 수 있으니 아래 흐름을 지켜 봅시다.

Loading diagram…
-- 일일 유지보수 묶음 (최근 파티션 컴팩션 + 정리)
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 의 고질병을 구조적으로 막을 수 있습니다.

마치며 — 핵심 요약

여기까지 따라왔다면 Iceberg 테이블 유지보수의 핵심을 이미 손에 쥔 셈입니다. 한번 더 정리해 볼게요.

  • 세 가지 원인 — 작은 파일·스냅샷 누적·고아 파일이 Iceberg 성능 저하의 거의 전부입니다.
  • 진단 먼저$files·$snapshots·$partitions 메타데이터 테이블로 현황을 확인한 뒤 처방을 내리세요.
  • 순서 지키기OPTIMIZEexpire_snapshotsremove_orphan_files 순으로 실행해야 각 단계 효과가 제대로 나타납니다.
  • 범위를 좁히기 — 전체 테이블 OPTIMIZE는 비용이 큽니다. WHERE 절로 최근 파티션만 대상으로 삼는 것이 훨씬 효율적입니다.
  • retention_threshold 는 넉넉하게 — 7일 이하로 줄이면 time travel 여력이 사라지고, 진행 중인 커밋이 고아로 오삭제될 수 있습니다.
  • 자동화로 구조적으로 막기 — Airflow 나 cron 으로 이 루틴을 정기 실행하면 "시간이 지날수록 느려지는" 고질병을 구조적으로 예방할 수 있습니다.

이 루틴 하나만 갖춰도 Iceberg 테이블은 오래 써도 처음 성능을 유지할 수 있습니다. 유지보수 자동화나 성능 저하 진단에 궁금한 점이 생기면 언제든 편하게 문의해 주세요!


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

— Data Dynamics 엔지니어링 팀