Snowflake는 사용한 만큼만 비용이 청구되는 구조이기 때문에, 비용이 어디서, 왜 발생하는지 이해하는 것이 최적화의 출발점입니다. 이 글에서는 Snowflake의 비용 구성 요소부터 실무에서 바로 활용할 수 있는 모니터링·최적화 쿼리까지 정리했습니다.
Snowflake 비용은 크게 컴퓨팅, 스토리지, 데이터 전송 세 가지로 나뉩니다.
컴퓨팅 리소스를 사용하는 경우는 다음과 같습니다.
비용 관리 프레임워크는 가시화 → 통제 → 최적화 흐름으로 Snowflake 비용을 체계적으로 관리하는 방법입니다.
비용의 패턴을 파악하고, 누가 어떤 목적으로 비용을 발생시켰는지 확인하는 단계입니다.
Snowflake Dashboard > Admin > Cost Management 에서 확인할 수 있습니다.
예산 한도와 가드레일을 설정하고 모니터링하는 단계입니다.
Resource Monitor 구성

-- Warehouse 목록 조회
SHOW WAREHOUSES;
-- Resource Monitor를 사용하지 않는 Warehouse 조회
SHOW WAREHOUSES;
SELECT "name" AS WAREHOUSE_NAME, "size" AS WAREHOUSE_SIZE
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "resource_monitor" = 'null';
-- Auto-Suspend(자동 중단)가 1시간 이상인 Warehouse 조회
SHOW WAREHOUSES;
SELECT "name" AS WAREHOUSE_NAME, "size" AS WAREHOUSE_SIZE
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "auto_suspend" >= 3600; -- 3600초 = 1시간
-- Auto-Resume가 False인 Warehouse 조회
SHOW WAREHOUSES;
SELECT "name" AS WAREHOUSE_NAME, "size" AS WAREHOUSE_SIZE
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()))
WHERE "auto_resume" = 'false';
적절한 Warehouse 타입 선택과 크기 조정을 통해 비용을 최적화하는 단계입니다.
Standard(일반형), Snowpark-optimized Warehouse(대용량 메모리형) 두 가지메모리 부족 → Warehouse의 Local Disk로 spill → Local Disk 부족 → Remote Storage로 spill
⚠️ spill이 발생할수록 데이터를 얻기까지의 시간과 비용이 증가합니다.
USE WAREHOUSE compute_s;
SELECT query_id,
SUBSTR(query_text, 1, 50) AS partial_query_text,
user_name, warehouse_name, warehouse_size,
bytes_spilled_to_remote_storage,
start_time, end_time,
total_elapsed_time / 1000 AS elapsed_sec,
total_elapsed_time
FROM snowflake.account_usage.query_history
WHERE bytes_spilled_to_remote_storage > 0
AND start_time::date > DATEADD('days', -45, CURRENT_DATE)
ORDER BY bytes_spilled_to_remote_storage DESC
LIMIT 10;
결과가 있다면 해당
query_id로 쿼리를 추적한 뒤, 최적화 필요 여부를 판단합니다.
SELECT WAREHOUSE_NAME,
COUNT(*) AS QUERY_COUNT,
SUM(BYTES_SCANNED) AS BYTES_SCANNED,
SUM(BYTES_SCANNED * PERCENTAGE_SCANNED_FROM_CACHE) AS BYTES_SCANNED_FROM_CACHE,
SUM(BYTES_SCANNED * PERCENTAGE_SCANNED_FROM_CACHE) / SUM(BYTES_SCANNED) AS PERCENT_SCANNED_FROM_CACHE
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD('DAYS', -45, CURRENT_TIMESTAMP())
AND BYTES_SCANNED > 0
GROUP BY 1
ORDER BY 5;
PERCENT_SCANNED_FROM_CACHE비율이 낮다면, 캐시를 활용할 수 있도록 쿼리 튜닝을 고려합니다.
SELECT TO_DATE(START_TIME) AS DATE,
WAREHOUSE_NAME,
SUM(AVG_RUNNING) AS SUM_RUNNING,
SUM(AVG_QUEUED_LOAD) AS SUM_QUEUED
FROM SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_LOAD_HISTORY
WHERE TO_DATE(START_TIME) >= DATEADD('DAYS', -45, CURRENT_TIMESTAMP())
GROUP BY 1, 2
HAVING SUM(AVG_QUEUED_LOAD) > 0;
- Warehouse 부하는 쿼리 실행 시 queue에 얼마나 작업이 쌓였는지로 확인할 수 있습니다.
SUM_QUEUED >= 1이면 Warehouse 크기 확장을 고려합니다.
SELECT USER_NAME,
COUNT(*) AS COUNT_OF_QUERIES
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE START_TIME >= DATEADD(month, -1, CURRENT_TIMESTAMP())
AND PARTITIONS_SCANNED > (PARTITIONS_TOTAL * 0.95)
AND QUERY_TYPE NOT LIKE 'CREATE%'
GROUP BY 1
ORDER BY 2 DESC;

drop + create 동작 주의drop 후 create 하면 __DBT_BACKUP 접미사가 붙은 백업 테이블이 생성됩니다.| 용어 | 설명 |
|---|---|
| Object | Snowflake의 관리 대상 (Database, Warehouse 등) |
| Auto-Suspend | 일정 시간 미사용 시 Warehouse 자동 중단 |
| Auto-Resume | 쿼리 요청 시 중단된 Warehouse 자동 재개 |