마이크로 파티션과 클러스터링 (프루닝, 클러스터링 키, Optima Clustering)
Snowflake 가 데이터를 마이크로 파티션으로 나눠 저장하고 메타데이터로 읽을 파티션을 걸러 내는 원리, 클러스터링 키를 언제 거는지, 2026년 9월부터 바뀐 Optima Clustering 과금, 상태를 확인하는 함수까지 정리합니다.
마이크로 파티션이란
테이블에 행이 들어오면 Snowflake 는 들어온 순서대로 행을 묶어 마이크로 파티션을 만듭니다. 파티션 하나는 압축 전 50~500 MB 정도이고, 안에서는 열 단위로 따로 압축됩니다. 사용자가 파티션을 정의하지 않는다는 점이 전통적인 데이터베이스 파티션과 가장 큰 차이입니다.
Snowflake 는 파티션마다 다음 메타데이터를 클라우드 서비스 계층에 들고 있습니다.
- 열별 최솟값, 최댓값
- 열별 고유값 수, NULL 수
- 행 수, 파일 크기 같은 통계
이 메타데이터 덕분에 COUNT(*), MIN, MAX 같은 쿼리는 웨어하우스 없이도 답이 나오고, 조건이 있는 쿼리는 읽을 필요가 없는 파티션을 미리 빼고 시작합니다. 이것을 프루닝(pruning) 이라고 합니다.
프루닝이 잘 되는 조건
-- 이벤트 테이블에 날짜 조건을 주면, 날짜 범위가 겹치지 않는 파티션은 아예 읽지 않음
SELECT user_id, COUNT(*)
FROM analytics.events
WHERE event_date BETWEEN '2026-10-01' AND '2026-10-07'
GROUP BY user_id;Query Profile 의 TableScan 노드에서 Partitions scanned 와 Partitions total 을 비교하면 프루닝이 얼마나 되었는지 바로 보입니다. 전체의 몇 퍼센트만 읽었다면 잘 된 것이고, 거의 전부 읽었다면 아래를 의심합니다.
| 원인 | 예 | 해결 |
|---|---|---|
| 데이터가 조건 열 기준으로 섞여 있음 | 여러 날짜가 모든 파티션에 골고루 | 적재 순서 정렬, 클러스터링 키 |
| 조건 열에 함수를 씌움 | WHERE TO_CHAR(ts, 'YYYY-MM') = '2026-10' | WHERE ts >= '2026-10-01' AND ts < '2026-11-01' |
| 타입이 달라 암묵 변환 | 문자 열과 숫자 비교 | 같은 타입으로 비교 |
| JOIN 조건으로만 거름 | 작은 차원 테이블의 조건 | 런타임 조인 필터가 동작하는지 프로필 확인, 필요하면 조건을 큰 테이블에도 직접 |
자연 클러스터링
시간 순서대로 들어오는 데이터는 별도 작업 없이 날짜 기준으로 잘 모여 있습니다. 이를 자연 클러스터링이라고 합니다. 문제는 다음 경우입니다.
- 과거 데이터를 뒤늦게 대량 백필함
- UPDATE, MERGE 가 잦아 파티션이 계속 다시 쓰임
- 날짜가 아닌 열(고객 ID, 지역)로 주로 거름
클러스터링 키
클러스터링 키를 걸면 Snowflake 가 백그라운드에서 그 키 기준으로 파티션을 다시 정리합니다. 이를 Automatic Clustering 이라고 하며 서버리스로 돌고 웨어하우스를 쓰지 않습니다.
ALTER TABLE analytics.events CLUSTER BY (event_date, tenant_id);
-- 상태 확인: 평균 깊이(average_depth)가 낮을수록 잘 정리된 것
SELECT SYSTEM$CLUSTERING_INFORMATION('analytics.events', '(event_date, tenant_id)');
-- 일시 중지, 재개
ALTER TABLE analytics.events SUSPEND RECLUSTER;
ALTER TABLE analytics.events RESUME RECLUSTER;언제 거나
- 테이블이 수 TB 이상이고 조회가 특정 열로 거르는 패턴이 분명할 때
- 조회 빈도가 높아서 줄어드는 스캔 비용이 정리 비용보다 클 때
- 키 순서는 보통 카디널리티가 낮은 열부터, 너무 고유한 열(타임스탬프 원본, UUID)은
DATE_TRUNC같은 식으로 낮춰서 겁니다.
걸지 말아야 할 때
- 작은 테이블 (수 GB 수준이면 효과가 거의 없음)
- 쓰기가 끊임없이 들어오고 조회는 드문 테이블
- 조회 조건이 매번 다른 탐색용 테이블 (이때는 검색 최적화 가 맞을 수 있음)
Optima Clustering 과 Clustering Classic
2026년 9월 1일부터 새로 클러스터링 키를 거는 테이블은 Optima Clustering 으로 정리됩니다. 이미 클러스터링되던 테이블은 Clustering Classic 으로 계속 돌고, 키를 바꿔도 Optima 로 옮겨 가지 않으며 옮기는 명령도 없습니다.
| 항목 | Clustering Classic | Optima Clustering |
|---|---|---|
| 과금 | 서버리스 컴퓨트 크레딧 (Consumption Table 배수 2) | 적재한 압축 전 GB 당 0.007 크레딧 x 겹침 정도(0~1) |
| 키 길이 | 키 열마다 앞 5바이트만 사용 | 모든 키 열 합쳐 1 KB 까지 |
| 특징 | 정리 작업량에 비례 | 잘 정렬되어 들어오는 추가 전용 데이터는 비용이 0 에 가까움 |
| 확인 | AUTOMATIC_CLUSTERING_HISTORY 의 VERSION 열이 CLASSIC | 같은 열이 OPTIMA |
주의 Optima 에서는
SUSPEND RECLUSTER로 멈춰도 다시 켜면 그동안 쌓인 데이터를 따라잡는 비용이 한 번에 나옵니다. 공식 문서도 비용 통제 목적의 일시 중지는 대개 효과가 없다고 안내합니다. 클러스터링을 완전히 그만두려면 키를 지웁니다 (ALTER TABLE ... DROP CLUSTERING KEY).
비용 추정은 SYSTEM$ESTIMATE_AUTOMATIC_CLUSTERING_COSTS 로 합니다. 다만 Optima 는 처음 정리 비용만 추정하고 유지 비용은 아직 내주지 않으며, 추정치와 실제가 최대 두 배까지 차이 날 수 있습니다.
-- 최근 30일 클러스터링 비용 상위 테이블
SELECT database_name, schema_name, table_name, version,
SUM(credits_used) AS credits
FROM snowflake.account_usage.automatic_clustering_history
WHERE start_time >= DATEADD(day, -30, CURRENT_TIMESTAMP())
GROUP BY 1, 2, 3, 4
ORDER BY credits DESC
LIMIT 20;적재 단계에서 정렬하기
클러스터링 키 없이도 적재할 때 ORDER BY 로 정렬해 넣으면 처음부터 잘 모인 파티션이 만들어집니다. 일회성 백필이나 재적재에 특히 효과적입니다.
INSERT OVERWRITE INTO analytics.events
SELECT * FROM analytics.events_backfill
ORDER BY event_date, tenant_id;팁 클론으로 만든 테이블은 Automatic Clustering 이 일시 중지된 상태로 시작합니다. 운영에서 클론을 떠서 대체 테이블로 쓸 때는
RESUME RECLUSTER를 잊지 마세요.
트러블슈팅
증상: 클러스터링 키를 걸었는데 비용만 늘고 쿼리는 그대로입니다.
원인: 키가 실제 조회 조건과 맞지 않거나, 키 열의 카디널리티가 너무 높습니다. Classic 에서는 문자열 키의 앞 5바이트만 보므로 앞부분이 같은 값이 많으면 정리가 되지 않습니다.
해결:
QUERY_HISTORY와 접근 기록으로 자주 거르는 열을 확인하고, 키를DATE_TRUNC나SUBSTR로 낮춘 식으로 바꿉니다.증상: Partitions scanned 가 total 과 거의 같습니다.
원인: 조건 열에 함수가 씌워졌거나 타입 변환이 일어났습니다.
해결: 조건을 열 그대로 비교하는 형태로 고치고 프로필을 다시 봅니다. 느린 쿼리 전체 순서는 느린 쿼리 트러블슈팅 에 있습니다.