동적 테이블 비용 이해하기

동적 테이블 비용 이해하기

이 페이지는 동적 테이블의 세 가지 비용 구성 요소(가상 웨어하우스 컴퓨팅, Cloud Services 컴퓨팅, 스토리지)를 설명하고, SQL로 그 비용을 추정·모니터링하는 방법, 그리고 예상치 못한 청구를 일으키는 일반적인 패턴을 다뤄요.

특정 동적 테이블의 비용을 알아보려면 이 쿼리로 시작하세요. 테이블·갱신 유형별로 갱신 활동을 요약해 몇 번의 갱신이 실행됐고 몇 행이 처리됐는지 보여줘요.

SELECT
    name,
    refresh_action,
    COUNT(*) AS refreshes,
    SUM(
        statistics:numInsertedRows::INT
        + statistics:numDeletedRows::INT
        + statistics:numCopiedRows::INT
    ) AS total_rows_processed
FROM
    TABLE(
        INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
            NAME_PREFIX => 'mydb.myschema.',
            RESULT_LIMIT => 1000
        )
    )
WHERE
    refresh_action != 'NO_DATA'
GROUP BY
    name, refresh_action
ORDER BY
    total_rows_processed DESC;
+-------------------------------------+----------------+-----------+-----------------------+
| NAME                                | REFRESH_ACTION | REFRESHES | TOTAL_ROWS_PROCESSED  |
|-------------------------------------+----------------+-----------+-----------------------|
| MYDB.MYSCHEMA.DT_ORDERS_DAILY      | INCREMENTAL    |        72 |                 48200 |
| MYDB.MYSCHEMA.DT_ORDERS            | INCREMENTAL    |       144 |                 12050 |
+-------------------------------------+----------------+-----------+-----------------------+

출처: Snowflake 문서

본문

세 가지 비용 구성 요소

모든 동적 테이블은 세 범주에서 비용이 발생해요. 각각의 상대적 비중은 갱신이 얼마나 자주 실행되는지, 웨어하우스 크기, 데이터 볼륨에 따라 달라져요.

구성 요소 비용을 좌우하는 요소 청구 방식
가상 웨어하우스 컴퓨팅 할당된 웨어하우스에서 실행되는 갱신 쿼리. 더 큰 웨어하우스나 더 빈번한 갱신은 비용을 증가. 웨어하우스 크기에 기반한 초당 크레딧. 자세한 내용은 컴퓨팅 비용 이해 문서 참조.
Cloud Services 컴퓨팅 업스트림 변경을 감지하고 웨어하우스 갱신이 필요한지 결정하는 메타데이터 검사. 데이터가 변경되지 않았어도 모든 갱신 주기에서 실행. 매일 청구되지만, Cloud Services 크레딧이 그날 총 웨어하우스 크레딧의 10%를 초과할 때만. 자세한 내용은 Cloud Services 청구 문서 참조.
스토리지 구체화된 결과, Time Travel 데이터, fail-safe 복사본. 증분 갱신은 행당 작은 메타데이터 컬럼을 추가. 표준 Snowflake 스토리지 요율. 자세한 내용은 스토리지 비용 이해 문서 참조. 동적 Apache Iceberg 테이블은 외부 스토리지를 사용하며 Snowflake 스토리지 비용이 발생하지 않음.

가상 웨어하우스 컴퓨팅 비용

가상 웨어하우스 컴퓨팅은 대부분의 동적 테이블 워크로드의 주요 비용이에요. 각 동적 테이블은 할당된 웨어하우스를 사용해 갱신을 실행해요. 갱신당 비용은 웨어하우스 크기, 정의의 복잡도, 처리되는 데이터 볼륨에 따라 달라져요. 웨어하우스 청구가 어떻게 작동하는지에 대한 완전한 세부 정보(초당 청구와 60초 최소값 포함)는 컴퓨팅 비용 이해 문서를 참조하세요.

주요 동작:

  • Snowflake가 업스트림 변경을 감지하지 못하면 웨어하우스는 일시 중단 상태로 유지되고 컴퓨팅 크레딧이 소비되지 않아요.
  • 기본 테이블에 변경이 있으면 필터링 후 갱신이 출력 행을 생성하지 않아도 웨어하우스는 다시 시작되고 갱신을 실행해요.
  • 일반 갱신용 웨어하우스(WAREHOUSE)와 재초기화용(INITIALIZATION_WAREHOUSE)을 별도로 할당할 수 있어요. 자세한 내용은 동적 테이블용 웨어하우스 선택 및 크기 조정 문서를 참조하세요.

특정 동적 테이블의 웨어하우스 크레딧 소비를 확인하려면 DYNAMIC_TABLE_REFRESH_HISTORY를 쿼리하고 QUERY_HISTORY와 조인하세요:

SELECT
    r.name AS dynamic_table_name,
    r.refresh_action,
    r.state,
    q.warehouse_size,
    q.credits_used_cloud_services,
    q.total_elapsed_time / 1000 AS elapsed_seconds
FROM
    TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
        NAME => 'mydb.myschema.dt_orders',
        RESULT_LIMIT => 10
    )) r
LEFT JOIN
    TABLE(INFORMATION_SCHEMA.QUERY_HISTORY()) q
    ON r.query_id = q.query_id
WHERE r.state = 'SUCCEEDED'
ORDER BY r.data_timestamp DESC;
+------------------------------+----------------+-----------+----------------+----------------------------------+------------------+
| DYNAMIC_TABLE_NAME           | REFRESH_ACTION | STATE     | WAREHOUSE_SIZE | CREDITS_USED_CLOUD_SERVICES      | ELAPSED_SECONDS  |
|------------------------------+----------------+-----------+----------------+----------------------------------+------------------+
| MYDB.MYSCHEMA.DT_ORDERS     | INCREMENTAL    | SUCCEEDED | X-Small        |                         0.000024 |             1.82 |
| MYDB.MYSCHEMA.DT_ORDERS     | INCREMENTAL    | SUCCEEDED | X-Small        |                         0.000019 |             0.94 |
+------------------------------+----------------+-----------+----------------+----------------------------------+------------------+

💡 테스트 중 동적 테이블 비용을 격리하려면 전용 웨어하우스를 사용하세요. 이렇게 하면 그 웨어하우스의 모든 크레딧을 동적 테이블 갱신에 귀속할 수 있어요. 비용 기준선을 확립한 후 동적 테이블을 공유 웨어하우스로 옮길 수 있어요. 자세한 내용은 동적 테이블용 웨어하우스 선택 및 크기 조정 문서를 참조하세요.

Cloud Services 비용과 10% 청구 임계값

Cloud Services 크레딧은 데이터가 변경됐는지와 관계없이 모든 갱신 주기에서 실행되는 메타데이터 작업(변경 감지, 쿼리 컴파일, 스케줄링)을 커버해요. 각 활성 동적 테이블은 이 오버헤드를 독립적으로 발생시켜요.

10% 임계값이 작동하는 방식

Cloud Services 크레딧은 일일 총액이 그날의 웨어하우스 컴퓨팅 크레딧의 10%를 초과할 때만 청구돼요. 이는 웨어하우스별·동적 테이블별이 아니라 계정 수준의 UTC 일일 계산이에요. 전체 청구 공식과 예시는 Cloud Services 사용에 대한 청구 이해 문서를 참조하세요.

짧은 target lag은 Cloud Services 비용을 증폭시킴 Cloud Services 비용은 활성 동적 테이블 수, target lag, 파이프라인 깊이에 따라 확장돼요. 각 동적 테이블은 모든 갱신 주기에서 독립적으로 변경 감지 검사를 수행해요. 짧은 target lag에 많은 동적 테이블이 있으면 Cloud Services 요금이 10% 임계값을 초과해 직접 청구를 초래할 수 있어요.

1분 target lag의 200개 동적 테이블 파이프라인은 하루 약 288,000회의 변경 감지 검사를 생성해요(200개 테이블 × 1,440 주기). 데이터가 전혀 변경되지 않아도 이 검사들은 Cloud Services 크레딧을 누적해요.

Cloud Services 비용을 줄이려면:

  • 거의 실시간 신선도가 필요하지 않은 곳에서 target lag을 늘리세요.
  • 파이프라인의 중간 동적 테이블에 TARGET_LAG = DOWNSTREAM을 사용해 필요할 때만 갱신되게 하세요.
  • 비프로덕션 환경에서 업무 시간 외에 동적 테이블을 일시 중단하세요.
  • METERING_HISTORY 뷰로 Cloud Services 소비를 모니터링하세요.

Cloud Services 비용을 좌우하는 일반적인 패턴은 비용을 위한 Cloud Services 최적화 문서를 참조하세요.

계정이 10% 임계값을 초과하는지 확인하세요:

SELECT
    START_TIME::DATE AS usage_date,
    ROUND(SUM(credits_used_compute), 2) AS compute_credits,
    ROUND(SUM(credits_used_cloud_services), 2) AS cs_credits,
    ROUND(SUM(credits_used_compute) * 0.10, 2) AS cs_included,
    ROUND(GREATEST(SUM(credits_used_cloud_services) - (SUM(credits_used_compute) * 0.10), 0), 2)
        AS cs_billed
FROM
    SNOWFLAKE.ACCOUNT_USAGE.METERING_HISTORY
WHERE
    start_time >= DATEADD('day', -7, CURRENT_TIMESTAMP())
GROUP BY usage_date
ORDER BY usage_date DESC;
+------------+-----------------+------------+-------------+-----------+
| USAGE_DATE | COMPUTE_CREDITS | CS_CREDITS | CS_INCLUDED | CS_BILLED |
|------------+-----------------+------------+-------------+-----------|
| 2025-01-20 |           50.00 |       6.00 |        5.00 |      1.00 |
| 2025-01-19 |           48.50 |       4.20 |        4.85 |      0.00 |
+------------+-----------------+------------+-------------+-----------+

스토리지 비용

동적 테이블은 구체화된 결과를 저장하며 표준 Snowflake 스토리지 비용이 발생해요. 스토리지가 청구되는 방식에 대한 일반 정보는 스토리지 비용 이해 문서를 참조하세요. 동적 테이블에 특히 총 스토리지 공간에 영향을 주는 몇 가지 요소가 있어요:

  • Time Travel과 fail-safe. 잦은 갱신은 Time Travel 데이터의 축적을 증가시켜요. Fail-safe는 추가 데이터 보호를 제공해요. fail-safe에서 스토리지 비용을 줄이려면 일시적(transient) 동적 테이블을 만드세요.
  • 증분 갱신 메타데이터. 증분 갱신을 사용하는 동적 테이블은 변경 추적을 위해 행당 내부 메타데이터 컬럼을 유지해요. 이는 컬럼 수와 무관하게 행당 일정량의 스토리지를 추가해요. 좁은 테이블(컬럼 수가 적은)에서는 이 오버헤드가 실제 데이터에 비해 상당할 수 있어요.
  • 복제. 교차 리전 복제에 참여하는 동적 테이블은 복제 비용이 발생해요. 자세한 내용은 다른 계정과 동적 테이블 공유 문서를 참조하세요.
  • 일시 중단된 동적 테이블. 일시 중단된 동적 테이블은 컴퓨팅 크레딧을 소비하지 않지만, 구체화된 데이터, Time Travel 기록, fail-safe 복사본에 대한 스토리지 요금은 여전히 발생해요. 일시 중단 전 갱신의 Time Travel 데이터는 DATA_RETENTION_TIME_IN_DAYS에 따라 정상적으로 만료돼요. 동적 테이블이 기본 테이블의 DATA_RETENTION_TIME_IN_DAYS 설정보다 오래 일시 중단 상태로 있으면 변경 추적 창이 만료되고 다시 시작될 때 재초기화해야 해요. 보존에 대한 자세한 내용은 데이터 보존 이해 문서를 참조하세요.
  • 스토리지 수명 주기 정책. 만료된 행을 비동기적으로 삭제하거나 아카이브하는 스토리지 수명 주기 정책을 연결해 동적 테이블의 스토리지 공간을 줄이세요. 자세한 내용은 동적 테이블과 스토리지 수명 주기 정책 사용 문서를 참조하세요.

📌 동적 Apache Iceberg 테이블은 Snowflake 스토리지 비용이 발생하지 않아요. 자세한 내용은 Iceberg 테이블 청구 문서를 참조하세요.

일반적인 비용 패턴

파이프라인에 이 패턴 중 하나가 적용되는지 확인하세요.

AUTO 모드가 경고 없이 전체 갱신을 선택

AUTO는 생성 시점에 갱신 모드를 한 번 결정해요. INCREMENTAL을 기대했는데 FULL로 결정되면, 모든 갱신이 변경된 행만이 아니라 전체 테이블을 다시 처리하므로 갱신 비용이 증가할 수 있어요. AUTO가 작동하는 방식과 해결된 모드를 확인하는 방법은 동적 테이블 갱신 모드 문서를 참조하세요.

짧은 target lag이 유휴 테이블에서 Cloud Services를 증폭

업스트림 변경이 드문 동적 테이블에 짧은 target lag(예: 1분)을 설정하면 NO_DATA 결과를 생성하는 반복적인 변경 감지 검사가 발생해요. 각 검사는 여전히 Cloud Services 크레딧을 발생시켜요.

NO_DATA 갱신 비율이 높은 동적 테이블을 찾으세요:

SELECT
    name,
    COUNT_IF(refresh_action = 'NO_DATA') AS no_data_refreshes,
    COUNT_IF(refresh_action != 'NO_DATA') AS data_refreshes,
    ROUND(no_data_refreshes / NULLIF(no_data_refreshes + data_refreshes, 0) * 100, 1)
        AS no_data_pct
FROM
    TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
        RESULT_LIMIT => 10000
    ))
GROUP BY name
HAVING no_data_pct > 50
ORDER BY no_data_refreshes DESC;
+-------------------------------+-------------------+----------------+-------------+
| NAME                          | NO_DATA_REFRESHES | DATA_REFRESHES | NO_DATA_PCT |
|-------------------------------+-------------------+----------------+-------------|
| MYDB.MYSCHEMA.DT_ORDERS      |              1200 |             80 |        93.8 |
| MYDB.MYSCHEMA.DT_ORDERS_DAILY |              950 |            120 |        88.8 |
+-------------------------------+-------------------+----------------+-------------+

동적 테이블의 NO_DATA 비율이 높으면 target lag을 늘리거나, 다운스트림 소비자가 트리거할 때만 갱신되도록 TARGET_LAG=DOWNSTREAM을 사용하는 것을 고려하세요.

TRUNCATE 다음 COPY INTO가 과도한 변경 이벤트를 생성

업스트림 기본 테이블이 TRUNCATE 다음에 COPY INTO 패턴으로 로드되면, 각 주기는 기존 행별 DELETE 이벤트와 로드된 행별 INSERT 이벤트를 생성해요. 동적 테이블 갱신이 실패하거나 뒤처지면 이 변경 이벤트가 누적돼요. 단일 복구 갱신이 전체 백로그를 처리해요.

이 패턴을 피하려면:

  • 업스트림 로딩에 TRUNCATE 다음 COPY INTO 대신 INSERT-only 또는 MERGE 패턴을 사용하세요.
  • 전체 교체 패턴(TRUNCATE 다음 COPY INTO, 또는 INSERT OVERWRITE)으로 로드되는 기본 테이블에 RELY가 있는 PRIMARY KEY를 추가하세요. Snowflake가 로드 전후의 키 값을 비교해 실제로 변경된 행만 처리해요. 자세한 내용은 모범 사례 4를 참조하세요.
  • 백로그가 쌓이지 않도록 실패한 갱신을 모니터링하세요. 자세한 내용은 동적 테이블 갱신 문제 트러블슈팅 문서를 참조하세요.

동적 테이블 비용 모니터링

다음 쿼리를 사용해 동적 테이블 파이프라인 전반의 비용을 추적하세요.

지난 7일의 웨어하우스별 크레딧 소비

가장 많은 크레딧을 소비하는 웨어하우스를 찾으려면 WAREHOUSE_METERING_HISTORY를 쿼리하세요. 동적 테이블에 전용 웨어하우스를 사용한다면 이 쿼리가 그 총 비용을 보여줘요.

SELECT
    warehouse_name,
    ROUND(SUM(credits_used), 2) AS total_credits,
    ROUND(SUM(credits_used_compute), 2) AS compute_credits,
    ROUND(SUM(credits_used_cloud_services), 2) AS cs_credits
FROM
    SNOWFLAKE.ACCOUNT_USAGE.WAREHOUSE_METERING_HISTORY
WHERE
    start_time >= DATEADD('day', -7, CURRENT_TIMESTAMP())
GROUP BY warehouse_name
ORDER BY total_credits DESC;
+----------------+---------------+-----------------+------------+
| WAREHOUSE_NAME | TOTAL_CREDITS | COMPUTE_CREDITS | CS_CREDITS |
|----------------+---------------+-----------------+------------|
| TRANSFORM_WH   |         42.50 |           40.00 |       2.50 |
| ANALYTICS_WH   |         28.30 |           27.10 |       1.20 |
+----------------+---------------+-----------------+------------+

동적 테이블별 갱신 활동

각 동적 테이블이 전체 갱신 볼륨에 어떻게 기여하는지 보려면 DYNAMIC_TABLE_REFRESH_HISTORY를 쿼리하세요. 갱신 횟수가 높거나 평균 지속 시간이 긴 동적 테이블을 최적화 후보로 찾으세요.

SELECT
    name,
    refresh_action,
    COUNT(*) AS refresh_count,
    AVG(TIMESTAMPDIFF('second', refresh_start_time, refresh_end_time)) AS avg_duration_sec,
    SUM(statistics:numInsertedRows::INT) AS total_inserted,
    SUM(statistics:numDeletedRows::INT) AS total_deleted
FROM
    TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
        RESULT_LIMIT => 10000
    ))
WHERE
    state = 'SUCCEEDED'
    AND data_timestamp >= DATEADD('day', -1, CURRENT_TIMESTAMP())
GROUP BY name, refresh_action
ORDER BY refresh_count DESC;
+-------------------------------+----------------+---------------+------------------+----------------+---------------+
| NAME                          | REFRESH_ACTION | REFRESH_COUNT | AVG_DURATION_SEC | TOTAL_INSERTED | TOTAL_DELETED |
|-------------------------------+----------------+---------------+------------------+----------------+---------------+
| MYDB.MYSCHEMA.DT_ORDERS      | INCREMENTAL    |           144 |              1.2 |          12050 |           200 |
| MYDB.MYSCHEMA.DT_ORDERS_DAILY | INCREMENTAL   |            72 |              3.8 |          48200 |          1100 |
+-------------------------------+----------------+---------------+------------------+----------------+---------------+

예상치 못하게 전체 갱신을 실행하는 동적 테이블 식별

REINITIALIZE 작업은 동적 테이블을 완전히 재처리하며 증분 갱신보다 훨씬 많은 비용이 들어요.

SELECT
    name,
    refresh_action,
    COUNT(*) AS refresh_count
FROM
    TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
        RESULT_LIMIT => 10000
    ))
WHERE
    refresh_action = 'REINITIALIZE'
    AND data_timestamp >= DATEADD('day', -7, CURRENT_TIMESTAMP())
GROUP BY name, refresh_action
ORDER BY refresh_count DESC;
+----------------------------------+----------------+---------------+
| NAME                             | REFRESH_ACTION | REFRESH_COUNT |
|----------------------------------+----------------+---------------|
| MYDB.MYSCHEMA.DT_ORDERS_DAILY   | REINITIALIZE   |            14 |
+----------------------------------+----------------+---------------+

동적 테이블이 빈번한 REINITIALIZE 작업을 보이면 재초기화를 트리거하는 업스트림 DDL 변경이나 정책 변경을 확인하세요. 자세한 내용은 동적 테이블 수정 문서를 참조하세요.

다음 단계

  • 올바른 웨어하우스 크기와 구성을 선택하려면, 동적 테이블용 웨어하우스 선택 및 크기 조정 문서를 참조하세요.
  • 쿼리 최적화로 갱신 비용을 줄이려면, 증분 갱신용 쿼리 최적화 문서를 참조하세요.
  • 모니터링 대시보드와 알림을 설정하려면, 동적 테이블 모니터링 문서를 참조하세요.

더 알아보기 (Learn more)