동적 테이블 의사결정 가이드
동적 테이블 의사결정 가이드
데이터 파이프라인에 어떤 방식을 쓸지 고민될 때, 이 가이드를 참고하면 돼요. 동적 테이블(dynamic tables), 스트림과 태스크(streams and tasks), 그리고 구체화된 뷰(materialized views) 중에서 상황에 맞는 방법을 고르는 기준을 정리했어요.
출처: Snowflake 문서
본문
의사결정 표(Decision table)
| 시나리오 | 동적 테이블 | 스트림과 태스크 | 구체화된 뷰 |
|---|---|---|---|
| 조인 또는 집계가 있는 SQL 기반 파이프라인 | 권장 | 가능 | 불가 (단일 테이블만 가능) |
| 다단계 선언형 파이프라인 (bronze/silver/gold) | 권장 | 가능 | 불가 |
| 변경된 데이터의 증분 처리 | 권장 (선언형) | 권장 (절차형) | 불가 |
| 단일 테이블 쿼리 가속화 | 가능 | 가능 | 권장 |
| 절차형 로직 (저장 프로시저, IF/ELSE, 루프) | 불가 | 권장 | 불가 |
| MERGE 또는 복잡한 upsert 패턴 | 불가 | 권장 | 불가 |
| 외부 함수 호출 또는 API 통합 | 불가 | 권장 | 불가 |
| 지연(lag) 없는 항상 최신 데이터 | 불가 (최소 TARGET_LAG 설정은 1분) |
가능 (태스크는 스케줄로 실행; 제로 랙은 아님) | 권장 |
| 투명한 쿼리 가속화 (옵티마이저가 미리 계산된 결과를 쓰도록 쿼리 재작성) | 불가 | 불가 | 권장 |
| 커스텀 스케줄링 또는 엄격한 오케스트레이션 제어 | 가능 (수동 트리거만; CRON이나 캐스케이드 없음) | 권장 | 불가 |
| UDF, UDTF, 또는 Snowpark를 쓰는 파이프라인 | 가능 (명시적 컬럼 목록의 스칼라 UDF와 UDTF; Snowpark는 지원 안 함) | 권장 | 불가 |
X가 필요하면 Y를 쓰세요
요구 사항을 올바른 방식과 매칭하기 위한 지침이에요.
선언형 SQL 파이프라인이 필요하면, 동적 테이블을 쓰세요
동적 테이블은 원하는 결과를 SELECT 문으로 정의하게 해줘요. 갱신 시점, 의존성 순서, 증분 처리는 Snowflake가 알아서 처리해요. 절차형 코드를 작성하거나 스트림을 관리하거나 태스크 파이프라인을 만들 필요가 없어요.
이 방식은 Snowflake에서 새로운 다중 테이블 SQL 파이프라인에 권장되는 방법이며, 특히 조인·집계·윈도우 함수가 있는 파이프라인에 적합해요.
절차형 로직 또는 커스텀 오케스트레이션이 필요하면, 스트림과 태스크를 쓰세요
스트림과 태스크는 파이프라인 로직에 대한 완전한 제어를 제공해요. 파이프라인에 저장 프로시저, MERGE 연산, 외부 함수 호출, 커스텀 재시도 로직, 또는 CRON 식을 이용한 명시적 스케줄링이 필요할 때 사용하세요. 자세한 내용은 스트림 소개 및 태스크 소개 문서를 참조하세요.
단일 테이블 쿼리 가속화가 필요하면, 구체화된 뷰를 쓰세요
구체화된 뷰는 단일 기본(base) 테이블에 대한 반복 쿼리를 가속화해요. 쿼리 옵티마이저가 쿼리를 구체화된 뷰를 사용하도록 자동으로 재작성하고, 데이터는 항상 최신 상태를 유지해요. 목표가 데이터 파이프라인 구축이 아니라 읽기 성능이라면 구체화된 뷰를 사용하세요. 자세한 내용은 구체화된 뷰 작업 문서를 참조하세요.
예시: 스트림과 태스크 vs 동적 테이블
다음 병렬 비교는 동일한 정의(원시 JSON 데이터에서 이름 추출)가 각 방식에서 어떻게 보이는지 보여줘요. 동적 테이블 버전은 스트림, 태스크, MERGE 로직을 하나의 단일 SELECT 문으로 대체해요.
스트림과 태스크 방식
- 랜딩 테이블을 생성해요.
- 랜딩 테이블에 스트림을 생성해요.
- 대상 타깃 테이블을 생성해요.
- 스트림 레코드를 처리하는
MERGE로직으로 태스크를 생성해요. - 태스크를 재개(resume)해요.
동적 테이블 방식
- 랜딩 테이블을 생성해요.
- 결과를 정의하는
SELECT로 동적 테이블을 생성해요.
| 스트림과 태스크 | 동적 테이블 |
|---|---|
| -- 원시 JSON 데이터를 저장할 랜딩 테이블 생성. CREATE OR REPLACE TABLE raw ( var VARIANT ); -- 랜딩 테이블에 대한 삽입을 -- 캡처할 스트림 생성. CREATE OR REPLACE STREAM rawstream1 ON TABLE raw ; -- 원시 데이터에서 사무실 방문자의 -- 이름을 저장할 테이블 생성. CREATE OR REPLACE TABLE names ( id INT , first_name STRING , last_name STRING ); -- rawstream1 스트림의 새 이름 레코드를 -- names 테이블에 삽입하는 태스크 생성. -- 스트림에 레코드가 있을 때 -- 매분 태스크 실행. CREATE OR REPLACE TASK raw_to_names WAREHOUSE = transform_wh SCHEDULE = ' 1 minute ' WHEN SYSTEM$STREAM_HAS_DATA ( ' rawstream1 ' ) AS MERGE INTO names n USING ( SELECT var:id id , var:fname fname , var:lname lname , metadata$action , metadata$isupdate FROM rawstream1 ) r1 ON n . id = TO_NUMBER ( r1 . id ) WHEN MATCHED AND metadata$action = ' DELETE ' AND NOT metadata$isupdate THEN DELETE WHEN MATCHED AND metadata$action = ' INSERT ' THEN UPDATE SET n . first_name = r1 . fname , n . last_name = r1 . lname WHEN NOT MATCHED AND metadata$action = ' INSERT ' THEN INSERT ( id , first_name , last_name ) VALUES ( r1 . id , r1 . fname , r1 . lname ); -- 태스크 시작. ALTER TASK raw_to_names RESUME ; | -- 원시 JSON 데이터를 저장할 랜딩 테이블 생성. CREATE OR REPLACE TABLE raw ( var VARIANT ); -- 원시 데이터에서 사무실 방문자의 -- 이름을 담는 동적 테이블 생성. -- 데이터를 기본(base) 테이블과 -- 1분 이내로 유지. CREATE OR REPLACE DYNAMIC TABLE dt_visitors TARGET_LAG = ' 1 minute ' WAREHOUSE = transform_wh REFRESH_MODE = INCREMENTAL AS SELECT var:id ::int id , var:fname ::string first_name , var:lname ::string last_name FROM raw ; |
동적 테이블 방식은 네 개의 객체와 MERGE 로직을 하나의 단일 SELECT 정의로 대체해요.
동적 테이블을 쓰지 말아야 할 때
파이프라인에 다음 요구 사항 중 하나라도 있다면 동적 테이블을 쓰지 마세요. 대신 아래에 적힌 대로 스트림과 태스크 또는 구체화된 뷰를 사용하세요.
출력 테이블에 DML이 필요할 때
동적 테이블은 읽기 전용이에요. INSERT, UPDATE, DELETE, TRUNCATE를 실행할 수 없어요. 출력에 직접 수정이 필요한 파이프라인(예: GDPR 삭제 요구 사항)이라면 표준 테이블과 스트림·태스크를 사용하세요.
저장 프로시저 또는 외부 함수가 필요할 때
동적 테이블 정의는 저장 프로시저, 외부 함수, 태스크를 호출할 수 없어요. 파이프라인에 절차형 로직, 조건 분기, 또는 외부 API 호출이 필요하다면 스트림과 태스크를 사용하세요.
분 미만의 데이터 신선도가 필요할 때
동적 테이블의 최소 목표 지연(target lag)은 1분이에요. 지연 없는 항상 최신 데이터가 필요하면 구체화된 뷰를 사용하세요. 커스텀 로직으로 분 미만 신선도가 필요하면 스트림과 태스크를 사용하세요.
MERGE 또는 복잡한 upsert 패턴이 필요할 때
동적 테이블은 선언형 모델을 사용하며 MERGE 문을 지원하지 않아요. 복합 키(compound key)를 가진 upsert 로직에 의존한다면 스트림과 태스크를 사용하세요.
서로게이트 키 생성이 필요할 때
동적 테이블은 증분 갱신 모드에서 시퀀스 함수(SEQ1, SEQ2)나 UUID_STRING을 지원하지 않아요. RANDOM()도 증분 갱신 모드에서 지원되지 않아요. 정의에 RANDOM()이 포함되면 AUTO는 FULL로 결정돼요. 이 함수들로 서로게이트 키를 생성한다면 스트림과 태스크를 사용하세요.
CURRENT_TIMESTAMP 같은 타임스탬프 함수는 WHERE/HAVING/QUALIFY 절에서 지원돼요. 전체 매트릭스는 지원 쿼리 문서를 참조하세요.
재초기화 없이 스키마 진화가 필요할 때
동적 테이블의 정의를 변경하면(예: 컬럼 추가) 재초기화(전체 테이블 재처리)가 트리거돼요. 모든 데이터를 재처리하지 않고 빈번한 스키마 변경이 필요하다면 ALTER TABLE과 함께 스트림·태스크를 사용하세요.
SCD Type 2 히스토리 추적이 필요할 때
동적 테이블은 데이터의 현재 상태를 나타내며 과거 기록(히스토리)을 보관하지 않아요. 시간에 따른 변경을 추적해야 한다면(천천히 변하는 차원 Type 2), 스트림과 태스크를 사용하세요.
정의가 간단한 단일 테이블 쿼리일 때
조인 없이 단일 기본 테이블에 대한 쿼리만 가속화하면 된다면 구체화된 뷰가 더 효율적이에요. 쿼리 옵티마이저는 쿼리를 구체화된 뷰를 사용하도록 자동 재작성하지만, 동적 테이블에서는 그렇게 되지 않아요.
주요 제한 사항
- 단일 계정은 최대 50,000개의 동적 테이블을 보유할 수 있어요.
- 동적 테이블에서 DML(
INSERT,UPDATE,DELETE,TRUNCATE)을 실행할 수 없어요. - 임시 동적 테이블을 만들 수 없어요.
- 동적 테이블은 디렉터리 테이블, 외부 테이블, 스트림, 또는 구체화된 뷰를 포함하는 소스를 지원하지 않아요.
- Frozen region 조건자에는 지원되는 표현식에 제한이 있어요. 자세한 내용은 Frozen regions and backfill 문서를 참조하세요.
전체 제한 사항 목록은 CREATE DYNAMIC TABLE 문서를 참조하세요.
다음 단계
방식을 고른 뒤에는:
- 첫 동적 테이블을 만들려면, 동적 테이블 생성 문서를 참조하세요.
- 갱신 모드 동작을 이해하려면, 동적 테이블 갱신 모드 문서를 참조하세요.
- 다중 테이블 파이프라인을 구성하려면, 동적 테이블의 목표 지연 설정 문서를 참조하세요.
- 동적 테이블 정의에서 지원되는 쿼리를 보려면, 동적 테이블 지원 쿼리 문서를 참조하세요.
- 스트림과 태스크를 선택했다면, 스트림 소개와 태스크 소개 문서를 참조하세요.
- 구체화된 뷰를 선택했다면, 구체화된 뷰 작업 문서를 참조하세요.