Frozen regions와 backfill

Frozen regions와 backfill

동적 테이블은 Snowflake가 테이블을 최신 상태로 유지하기 위해 주기적으로 다시 실행하는 쿼리로 정의돼요. 각 재실행을 갱신(refresh)이라고 해요.

frozen region은 Snowflake에 갱신 중 어떤 행을 건너뛸지 알려줘 갱신 비용을 줄여요.

📌 Frozen regions는 이전에 immutability constraints라고 불렸고, FROZEN WHERE 절은 이전에 IMMUTABLE WHERE 구문을 사용했어요. 레거시 IMMUTABLE WHERE 구문은 계속 지원되며, SHOW DYNAMIC TABLES는 여전히 immutable_where 컬럼을 사용해요.

절 하는 일 적용 대상
FROZEN WHERE 조건자와 일치하는 동적 테이블 행을 동결. 갱신은 그 행들을 건너뜀. 출력 측

다음 예시는 30일보다 오래된 출력 행을 동결해요:

-- Frozen region: 30일보다 오래된 출력 행 동결
CREATE OR ALTER DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < CURRENT_TIMESTAMP() - INTERVAL '30 days')
AS
  SELECT
    order_id, customer_id, order_date,
    ...
  FROM raw_orders
  WHERE order_status != 'returned';

전체 dt_orders 컬럼 목록은 동적 테이블 만들기 문서를 참조하세요.

출처: Snowflake 문서

본문

Frozen regions가 작동하는 방식

frozen region 조건자와 일치하는 행은 frozen region에 있어요. 일치하지 않는 행은 active region에 있어요. 각 갱신 중 Snowflake는 active region만 갱신해요.

핵심 동작:

  • 초기 갱신: 초기화 중에는 조건자가 무시되고 모든 행이 계산돼요.
  • 이후 갱신: 갱신 모드와 관계없이 active region만 갱신돼요.
  • 재초기화: 재초기화 중에도 active region만 갱신돼요.
  • 스토리지 수명 주기 정책: 동적 테이블에 스토리지 수명 주기 정책과 frozen region이 모두 있으면 정책 조건자는 추가 frozen region 역할을 해요. frozen region과 만료 region 양쪽에 속하는 행은 정책이 실행될 때 여전히 삭제돼요. 자세한 내용은 동적 테이블과 스토리지 수명 주기 정책 사용 문서를 참조하세요.
  • 기본 테이블의 데이터 거버넌스 정책: 동결된 행이 존재한 후 기본 테이블에 데이터 거버넌스 정책을 적용하거나 변경하면, frozen region의 행은 정책이 적용·변경되기 전의 값을 유지해요. 동결된 행에 정책을 적용하려면 동적 테이블에 직접 적용하세요. 관련 주의 사항은 컬럼 수준 보안 고려 사항 문서를 참조하세요.

frozen region 조건자는 서브쿼리, 비결정적 함수(타임스탬프 함수 제외), 사용자 정의·외부 함수, 또는 메타데이터 컬럼을 포함할 수 없어요. 조건자의 컬럼은 기본 테이블의 컬럼이 아니라 동적 테이블의 컬럼이어야 해요. 제한 사항의 전체 목록은 Frozen region 사용 참고 사항 문서를 참조하세요.

어떤 행이 동결됐는지 확인하려면 METADATA$IS_FROZEN 메타데이터 컬럼을 쿼리하세요:

SELECT
  order_id,
  order_date,
  line_total,
  METADATA$IS_FROZEN AS is_frozen
FROM dt_orders
ORDER BY order_date DESC
LIMIT 5;
+----------+-------------------------+------------+-----------+
| ORDER_ID | ORDER_DATE              | LINE_TOTAL | IS_FROZEN |
|----------+-------------------------+------------+-----------|
| 1005     | 2025-01-16 11:30:00.000 |      49.99 | FALSE     |
| 1004     | 2025-01-16 10:00:00.000 |      62.50 | FALSE     |
| 1003     | 2025-01-15 14:20:00.000 |      59.98 | TRUE      |
| 1002     | 2025-01-15 09:45:00.000 |      49.99 | TRUE      |
| 1001     | 2025-01-15 08:30:00.000 |      89.97 | TRUE      |
+----------+-------------------------+------------+-----------+

BACKFILL FROM으로 동적 테이블 시딩

BACKFILL FROM은 기존 데이터를 재계산하지 않고 새 동적 테이블에 복사해요. 기존 파이프라인을 마이그레이션하거나, 테이블에 수년간의 과거 데이터가 있을 때 값비싼 초기화를 피하거나, 데이터 문제에서 복구하는 데 backfill을 사용하세요.

BACKFILL FROM은 CREATE DYNAMIC TABLE에서만 사용할 수 있어요. ALTER로 기존 동적 테이블에 backfill을 추가할 수 없어요.

backfill 소스는 동적 테이블과 같은 순서로 일치하는 컬럼과 호환 가능한 데이터 타입을 포함해야 해요. 또한 AT 또는 BEFORE 절을 사용해 특정 시점을 지정해 특정 Time Travel 스냅샷에서 데이터를 복사할 수 있어요.

BACKFILL FROM을 frozen region과 결합하면:

  • frozen region은 backfill 소스에서 클론돼요.
  • active region은 정의에서 계산돼요.

frozen regions와 backfill로 작업할 때 다음 제한 사항이 적용돼요:

  • 현재 backfill에는 일반 테이블과 동적 테이블만 사용할 수 있어요.
  • backfill 테이블에서 복사되므로 새 동적 테이블에 정책이나 태그를 지정할 수 없어요.
  • 새 동적 테이블과 backfill 테이블의 클러스터링 키는 같아야 해요.
-- dt_orders_snapshot은 과거 주문 데이터를 포함한 일반 테이블 또는 클론입니다.
-- snapshot에서 frozen region을 backfill하고, 정의에서 최근 데이터를 계산합니다.

CREATE OR REPLACE DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < '2025-01-01')
  BACKFILL FROM dt_orders_snapshot
AS
  SELECT
    order_id, customer_id, order_date,
    ...
  FROM raw_orders
  WHERE order_status != 'returned';

AT 또는 BEFORE 절을 사용해 특정 Time Travel 스냅샷에서 backfill할 수도 있어요:

-- 특정 시점의 Time Travel 스냅샷에서 backfill.
CREATE OR REPLACE DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < '2025-01-01')
  BACKFILL FROM dt_orders_snapshot AT (TIMESTAMP => '2025-04-01 12:00:00'::TIMESTAMP_NTZ)
AS
  SELECT
    order_id, customer_id, order_date,
    ...
  FROM raw_orders
  WHERE order_status != 'returned';
-- 특정 문이 실행되기 직전에서 backfill.
CREATE OR REPLACE DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < '2025-01-01')
  BACKFILL FROM dt_orders_snapshot BEFORE (STATEMENT => '<statement_id>')
AS
  SELECT
    order_id, customer_id, order_date,
    ...
  FROM raw_orders
  WHERE order_status != 'returned';

전체 dt_orders 컬럼 목록은 동적 테이블 만들기 문서를 참조하세요.

Frozen region 추가 또는 제거

CREATE OR ALTER DYNAMIC TABLE 또는 ALTER DYNAMIC TABLE를 사용해 기존 동적 테이블에 frozen region을 추가, 변경, 또는 제거할 수 있어요. frozen region을 추가하거나 확장해도 재초기화가 트리거되지 않아요. 축소하거나 제거하면 트리거돼요.

Frozen region 조건자 변경

frozen region 조건자를 추가하거나 변경하려면 FROZEN WHERE 절과 함께 CREATE OR ALTER DYNAMIC TABLE을 사용하세요:

CREATE OR ALTER DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < '2025-01-01')
AS
  SELECT
    order_id, customer_id, order_date,
    ...
  FROM raw_orders
  WHERE order_status != 'returned';

SET FROZEN WHERE 절과 함께 ALTER DYNAMIC TABLE도 사용할 수 있어요:

ALTER DYNAMIC TABLE dt_orders
  SET FROZEN WHERE (order_date < '2025-01-01');

조건자를 변경하면 전체가 확장되느냐 축소되느냐에 따라 active region의 재초기화를 트리거할 수 있어요.

frozen region을 확장하는 변경(예: <=2023에서 <=2024)은 재초기화를 트리거하지 않아요. 축소하거나 형태를 바꾸는 변경(예: <'2025-01-02'에서 <'2025-01-01')은 재초기화를 트리거해요. 이 유형의 변경을 적용하려면 업데이트된 조건자와 함께 위에 표시된 접근 방식 중 하나를 사용하세요.

Frozen region 제거

⚠️ frozen region을 제거하면 다음 갱신에서 전체 재초기화가 트리거돼요. 이전에 frozen region에 있었던 행을 포함해 모든 행을 다시 처리해요.

FROZEN WHERE 절 없이 CREATE OR ALTER DYNAMIC TABLE을 사용하거나 ALTER DYNAMIC TABLE <name> UNSET FROZEN WHERE를 실행해 frozen region을 제거하세요.

Frozen region으로 DML

동적 테이블의 frozen region에 DML(INSERT, UPDATE, MERGE, DELETE)을 실행할 수 있어요. 이는 시간에 민감한 GDPR 삭제나 변경된 레코드 따라잡기 같은 사용 사례를 모든 행을 다시 처리하는 비용 없이 가능하게 해요.

DELETE FROM dt_orders
  WHERE customer_id = 105;

Frozen region 확인

동적 테이블의 frozen region 조건자를 보려면 SHOW DYNAMIC TABLES를 실행하고 immutable_where 컬럼을 확인하세요. 컬럼은 조건자 텍스트를 표시하고, 절이 설정되지 않았으면 NULL을 표시해요:

SHOW DYNAMIC TABLES LIKE 'dt_orders';
+------------+-------------------------------------------+
| name       | immutable_where                           |
|------------+-------------------------------------------|
| DT_ORDERS | order_date < '2025-01-01'::TIMESTAMP_NTZ  |
+------------+-------------------------------------------+

개별 행 상태를 확인하려면 METADATA$IS_FROZEN을 쿼리하세요:

SELECT
  COUNT_IF(METADATA$IS_FROZEN) AS frozen_rows,
  COUNT_IF(NOT METADATA$IS_FROZEN) AS active_rows
FROM dt_orders;
+-------------+-------------+
| FROZEN_ROWS | ACTIVE_ROWS |
|-------------+-------------|
|           3 |           2 |
+-------------+-------------+

RELY 제약 조건과의 상호작용

RELY 제약 조건은 옵티마이저에게 기본 키 또는 고유 제약 조건이 유지된다고 신뢰하라고 알려주며, 그걸 강제하지는 않아요. 동적 테이블에 frozen region과 RELY 제약 조건이 하나 이상 있으면 조건자의 컬럼이 테이블의 모든 RELY PRIMARY KEY와 RELY UNIQUE 제약 조건에 나타나야 해요. 다시 말해, 조건자 컬럼은 모든 RELY 제약 조건 컬럼 집합의 교집합에 있어야 해요.

테이블 제약 조건 frozen region 조건자에 허용됨
(A, B)의 RELY primary key, (B, C)의 RELY unique B만
(A)의 RELY primary key, (A, B)의 RELY unique A만

Snowflake는 조건자나 RELY 제약 조건을 추가하거나 변경할 때 이 규칙을 검증해요. 결과 상태가 규칙을 위반하면 문이 실패해요.

📌 RELY 제약 조건은 CREATE DYNAMIC TABLE 컬럼 목록에서 선언할 수 없어요. 동적 테이블에 기본 키 또는 고유 제약 조건을 추가하려면 테이블 생성 후 ALTER TABLE <name> ADD CONSTRAINT ... RELY를 사용하세요.

다음 예시는 성공하는 ALTER TABLE 문 하나와 실패하는 하나를 보여줘요. 첫 번째는 order_date가 RELY 기본 키에 있으므로 성공해요. 두 번째는 order_date가 기본 키에는 있지만 고유 제약 조건의 컬럼에 없어 모든 RELY 제약 조건의 교집합에 없으므로 실패해요:

CREATE OR REPLACE DYNAMIC TABLE dt_orders
  TARGET_LAG = '10 minutes'
  WAREHOUSE = transform_wh
  FROZEN WHERE (order_date < '2025-01-01')
AS
  SELECT
    order_id,
    order_date,
    customer_id,
    line_total
  FROM raw_orders;

-- 성공: order_date가 RELY 기본 키에 있음.
ALTER TABLE dt_orders ADD CONSTRAINT pk_orders PRIMARY KEY (order_id, order_date) RELY;

-- 실패: uq_customer가 order_date를 포함하지 않아, 더 이상 order_date가
-- 모든 RELY 제약 조건의 교집합에 없음.
ALTER TABLE dt_orders ADD CONSTRAINT uq_customer UNIQUE (order_id, customer_id) RELY;
002857 (55000): If a FROZEN WHERE clause is used with a PRIMARY KEY RELY constraint or a
UNIQUE RELY constraint, the column(s) used in the FROZEN WHERE clause must be a subset of
the intersection of the columns used in the RELY constraints. If no such column exists, the
specified FROZEN WHERE clause or RELY constraint cannot be used together.

다음 단계

  • 컴퓨팅 비용에 대한 정보는 동적 테이블 비용 이해 문서를 참조하세요.
  • 갱신 모드에 영향을 주는 쿼리 구조 제한 사항은 동적 테이블 지원 쿼리 문서를 참조하세요.
  • 갱신 작업을 모니터링하려면 동적 테이블 모니터링 문서를 참조하세요.

더 알아보기 (Learn more)