Snowflake configurations

Snowflake configurations

dbt-snowflake 어댑터에서 모델을 구성하는 방법을 다루는 페이지예요. dynamic table, interactive table, semantic view, temporary/transient table, merge 동작, 클러스터링, Python 모델, 가상 웨어하우스, grants, 보안 뷰 등을 설정할 수 있어요.

출처: 문서

본문

Snowflake 컬럼 크기 변경

Snowflake는 2026년 9월에 string/binary 데이터 타입의 기본 컬럼 크기 증가를 계획하고 있어요. 이 변경이 배포되면 dbt-snowflake v1.10.6 미만 버전은 특정 incremental 모델을 빌드하지 못할 수 있어요.

dbt-snowflake v1.10.6 미만을 쓰거나 dbt 플랫폼에서 아직 릴리스 트랙으로 마이그레이션하지 않았다면, 어댑터 버전이 이 변경과 호환되지 않아 다음 두 조건을 모두 충족하는 incremental 모델을 빌드하지 못할 수 있어요.

  • collation이 정의된 string 컬럼 포함
  • on_schema_change='sync_all_columns' config 사용

이 변경이 프로젝트에 영향을 주는지 확인하려면 다음 list 명령을 실행하세요.

dbt ls -s config.materialized:incremental,config.on_schema_change:sync_all_columns --resource-type model
  • 명령이 No nodes selected!를 반환하면 필요한 조치는 없어요.
  • 명령이 모델 하나 이상을 반환하면(예: Found 1000 models, 644 macros), 그 모델들에 너비를 지정하지 않은 string 컬럼이 있다면 영향을 받을 수 있어요. 그럴 땐 수정이 포함된 버전으로 업그레이드하세요.

dbt v1: dbt-snowflake v1.10.6 이상. 업그레이드 지침은 dbt v1 설치 안내의 Upgrade adapters를 참고하세요.

  • dbt platform: 모든 릴리스 트랙 (v1 Latest, v1 Compatible, v1 Extended, v1 Fallback).
  • dbt v2: v2.0.0.

이렇게 하면 incremental 모델이 필요한 collation 설정을 유지하면서 스키마 변경을 안전하게 처리할 수 있어요.

Iceberg 테이블 형식

Snowflake Iceberg 테이블 내용은 새 페이지로 이동했어요!

Dynamic tables

Snowflake 어댑터는 dynamic table을 지원해요. 이 materialization은 Snowflake 전용이라, dbt에서 view처럼 일반적으로 따라오는 모델 구성이 dynamic table에는 없을 수 있어요. 이 격차는 향후 패치와 버전에서 줄어들 거예요. 이 materialization은 Snowflake 전용이지만 materialized view의 구현을 크게 따르고 있어요. 특히 dynamic table은 on_configuration_change 설정에 접근할 수 있어요.

Dynamic table은 다음 구성 파라미터로 지원돼요.

(dbt v1.12 이상 적용)

dbt_project.yml

models:
  <resource-path>:
    +materialized: dynamic_table
    +on_configuration_change: apply | continue | fail
    +target_lag: downstream | <time-delta>
    +scheduler: ENABLE | DISABLE
    +snowflake_warehouse: <warehouse-name>
    +snowflake_initialization_warehouse: <warehouse-name>
    +refresh_warehouse: <warehouse-name>
    +refresh_mode: AUTO | FULL | INCREMENTAL
    +initialize: ON_CREATE | ON_SCHEDULE
    +cluster_by: <column-name> | [<column-name>, <column-name>, ...]
    +immutable_where: <condition>
    +copy_grants: true | false
    +transient: true | false

models/properties.yml

models:
  - name: [<model-name>]
    config:
      materialized: dynamic_table
      on_configuration_change: apply | continue | fail
      target_lag: downstream | <time-delta>
      scheduler: ENABLE | DISABLE
      snowflake_warehouse: <warehouse-name>
      snowflake_initialization_warehouse: <warehouse-name>
      refresh_warehouse: <warehouse-name>
      refresh_mode: AUTO | FULL | INCREMENTAL
      initialize: ON_CREATE | ON_SCHEDULE
      cluster_by: <column-name> | [<column-name>, <column-name>, ...]
      immutable_where: <condition>
      copy_grants: true | false
      transient: true | false

models/.sql

{{ config(
    materialized="dynamic_table",
    on_configuration_change="apply" | "continue" | "fail",
    target_lag="downstream" | "<integer> seconds | minutes | hours | days",
    scheduler="ENABLE" | "DISABLE",
    snowflake_warehouse="<warehouse-name>",
    snowflake_initialization_warehouse="<warehouse-name>",
    refresh_warehouse="<warehouse-name>",
    refresh_mode="AUTO" | "FULL" | "INCREMENTAL",
    initialize="ON_CREATE" | "ON_SCHEDULE",
    cluster_by="<column-name>" | ["<column-name>", "<column-name>", ...],
    immutable_where="<condition>",
    copy_grants=true | false,
    transient=true | false,

) }}

이 파라미터들에 대해 Snowflake 문서에서 더 알아보세요.

Target lag

Snowflake는 자동 새로고침 스케줄링에 두 가지 구성 시나리오를 허용해요.

  • 시간 기반(Time-based){ seconds | minutes | hours | days } 형식의 값을 제공해요. 예를 들어 dynamic table을 30분마다 갱신해야 하면 target_lag='30 minutes'를 쓰세요.
  • Downstream — dynamic table이 다른 dynamic table에 참조될 때 적용돼요. 이 시나리오에서 target_lag='downstream'은 각 레이어가 아니라 대상에서 새로고침을 제어하게 해줘요.

(dbt v1.12 이상 적용)

target_lagscheduler의 상호작용

target_lagscheduler와 함께 dynamic table 새로고침이 어떻게 관리되는지 결정해요. Snowflake 문서에서 target_lag에 대해 더 알아보세요. Snowflake는 1분 이상의 target lag을 지원한다는 점에 유의하세요.

(dbt v1.12 이상 적용)

Scheduler

scheduler 파라미터는 dynamic table이 Snowflake의 백그라운드 스케줄러로 새로고침되는지, 외부 오케스트레이터(예: dbt)로 새로고침되는지 제어해요. Snowflake는 두 옵션을 허용해요.

  • ENABLE — Snowflake의 내장 스케줄러가 정의된 target_lag을 기반으로 dynamic table을 자동 새로고침해요. 새로고침은 의존성 그래프를 따라 캐스케이드되어 스냅샷 일관성을 유지해요. 이 옵션을 쓰면 target_lag 설정이 필수예요.
  • DISABLE — dynamic table이 Snowflake의 자동 백그라운드 새로고침에서 제외돼요. 수동으로 또는 Snowflake 외부 오케스트레이션을 통해(예: ALTER DYNAMIC TABLE ... REFRESH를 실행하는 dbt run으로) 새로고침을 트리거해야 해요. 이 옵션을 명시적으로 설정하면 target_lag을 지정하면 오류가 나요.

dbt 기본값은 Snowflake 고유 기본값과 다름: Snowflake 고유 DDL에서 SCHEDULER를 생략하면 ENABLE이 기본이고, TARGET_LAG는 필수예요. dbt에서 기본값은 DISABLE이에요. schedulertarget_lag도 지정하지 않으면 dbt는 scheduler: DISABLE로 dynamic table을 만들고 새로고침을 직접 관리해요. scheduler를 명시적으로 설정하지 않고 target_lag을 지정하면 dbt는 scheduler: ENABLE로 설정해요.

핵심 사항:

  • scheduler: DISABLEtarget_lag과 함께 명시적으로 설정하면 오류가 나요. scheduler를 생략하고 target_lag을 제공하면 dbt가 scheduler: ENABLE로 자동 설정해 충돌을 해결해요.
  • scheduler: DISABLE일 때 수동 새로고침은 업스트림 dynamic table 의존성을 자동으로 새로고침하지 않아요. 이는 격리 경계를 만들어, 전체 파이프라인을 트리거하지 않고 dbt가 특정 테이블 새로고침을 관리하게 해줘요. 반대로 ENABLE은 의존성 그래프를 따라 새로고침을 캐스케이드해요.
  • scheduler: DISABLE인 dynamic table이 다른 dynamic table에 의존하면, 다운스트림 테이블이 새로고침될 때 그 업스트림 테이블은 새로고침되지 않아요. dbt가 새로고침 순서를 명시적으로 관리해야 해요.

예를 들어 dbt가 새로고침을 관리하게 하려면(기본 동작):

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='MY_WH',
) }}

select * from {{ source('raw', 'events') }}

target lag으로 Snowflake 관리 스케줄링을 활성화하려면:

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='MY_WH',
    target_lag='5 minutes',
) }}

select * from {{ source('raw', 'events') }}

Snowflake 문서에서 scheduler에 대해 더 알아보세요.

(dbt v1.11 이상 적용)

Refresh warehouse

dbt-snowflake v1.11부터 모델 구성에서 refresh_warehouse 파라미터로 dynamic table의 자체 새로고침 작업에 별도 웨어하우스를 지정할 수 있어요. 이는 DDL 실행을 제어하는 snowflake_warehouse와 별개예요. refresh_warehouse를 설정하면 자동 새로고침에는 더 작은 웨어하우스를 쓰고, DDL 작업에는 더 큰 snowflake_warehouse를 유지할 수 있어요.

models/.sql

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='LARGE_EXECUTION_WH',
    refresh_warehouse='SMALL_REFRESH_WH',
    target_lag='1 hour'
) }}

select * from {{ source('raw', 'events') }}

핵심 사항:

  • refresh_warehouse를 설정하지 않으면 snowflake_warehouse가 DDL 실행과 자체 새로고침 작업 둘 다에 쓰여요.
  • 기존 dynamic table에서 full refresh 없이 refresh_warehouse를 바꿀 수 있어요.
  • 기본 동작으로 돌아가려면 모델 구성에서 refresh_warehouse 파라미터를 제거하거나 명시적으로 None으로 설정하세요.

Snowflake 문서에서 WAREHOUSE 파라미터에 대해 더 알아보세요.

(dbt v1.9 이상 적용)

Refresh mode

Snowflake는 refresh mode에 세 가지 옵션을 허용해요.

  • AUTO — 기본적으로 dynamic table의 incremental refresh를 강제해요. CREATE DYNAMIC TABLE 문이 incremental refresh 모드를 지원하지 않으면 dynamic table은 자동으로 full refresh 모드로 생성돼요.
  • FULL — incremental refresh가 가능하더라도 dynamic table의 full refresh를 강제해요.
  • INCREMENTAL — dynamic table의 incremental refresh를 강제해요. 기본이 되는 쿼리가 incremental refresh를 수행할 수 없으면 dynamic table 생성이 실패하고 오류 메시지를 표시해요.

Snowflake 문서에서 refresh_mode에 대해 더 알아보세요.

Initialize

Snowflake는 initialize에 두 옵션을 허용해요.

  • ON_CREATE — 생성 시 dynamic table을 동기적으로 새로고침해요. 이 새로고침이 실패하면 dynamic table 생성이 실패하고 오류 메시지를 표시해요.
  • ON_SCHEDULE — 다음 스케줄된 새로고침에 dynamic table을 새로고침해요.

Snowflake 문서에서 initialize에 대해 더 알아보세요.

(dbt v1.11 이상 적용)

Immutable where

Snowflake는 IMMUTABLE WHERE 절로 dynamic table의 특정 행을 불변으로 표시하게 해줘요. 이렇게 하면 새로고침 중 Snowflake가 일치하는 행에 갱신이나 삭제를 적용하지 않아, 이력 데이터가 그대로 유지되고 새로고침이 더 빨라져요. dbt v1.11부터 이 기능을 immutable_where 구성으로 설정할 수 있어요. 이 config는 SQL 조건 표현식을 받고, 일치하는 행은 불변으로 취급되어 이후 새로고침에서 갱신·삭제되지 않아요.

예를 들어 이력 데이터는 보통 변하지 않으므로 1일보다 오래된 데이터를 불변으로 표시하려면:

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='MY_WH',
    target_lag='1 hour',
    immutable_where='ts < CURRENT_TIMESTAMP() - INTERVAL \'1 DAY\''
) }}

select
    id,
    ts,
    value
from {{ source('raw', 'events') }}

핵심 사항:

  • 이 config는 렌더링된 결과가 유효한 Snowflake SQL 조건인 한 Jinja 렌더링(예: dbt 변수, 매크로)을 지원해요.
  • 기존 dynamic table에서 불변 제약을 제거하려면 immutable_whereNone으로 설정하세요.
  • full refresh 없이 immutable_where 변경 사항을 적용할 수 있어요.

Snowflake 문서에서 IMMUTABLE WHERE에 대해 더 알아보세요.

Copy grants (dynamic tables)

dbt-snowflake v1.11부터 dbt가 CREATE OR REPLACE DYNAMIC TABLE 문을 생성할 때 copy_grants로 기존 객체 레벨 권한을 보존할 수 있어요. 비활성화하면 테이블이 재생성될 때 부여된 모든 권한이 드롭되어, grants를 수동으로 다시 적용할 때까지 다운스트림 사용자·롤이 접근을 잃어요. dynamic table에 copy_grants: true를 설정하면 dbt가 CREATE OR REPLACE DYNAMIC TABLE 문에 COPY GRANTS 절을 추가해요. 이렇게 하면 --full-refresh 실행 중 테이블의 기존 객체 레벨 권한이 보존되어, 테이블 재생성 후 접근을 다시 부여할 필요가 없어요.

copy_grants 파라미터를 구성하려면:

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='MY_WH',
    target_lag='1 hour',
    copy_grants=true
) }}

select * from {{ source('raw', 'events') }}

Snowflake 문서에서 COPY GRANTS에 대해 더 알아보세요.

(dbt v1.12 이상 적용)

Transient (dynamic tables)

저장 비용을 줄이기 위해 dynamic table을 transient로 만들 수 있어요. Transient dynamic table은 Snowflake의 Fail-safe 기간을 사용하지 않아 영구(permanent) dynamic table보다 저장 공간을 덜 써요. 모델 구성에서 transient: true로 dynamic table을 transient로 만들 수 있어요. 모든 dynamic table을 기본적으로 transient로 만들고 싶다면(각각 transient: true를 설정하지 않고) dbt_project.yml에서 snowflake_default_transient_dynamic_tables 플래그를 활성화하세요. 이 플래그는 기본값이 false라, dynamic table은 기본적으로 영구로 생성돼요.

핵심 사항:

  • transient: true를 설정하면 CREATE DYNAMIC TABLE 문에 TRANSIENT 키워드로 dynamic table이 생성돼요.
  • Snowflake는 기존 dynamic table의 transient 속성 변경을 지원하지 않아요. transienttrue에서 false(또는 반대)로 바꾸면 전체 테이블 재생성이 트리거돼요.
  • transient를 지정하지 않았을 때 모든 새 dynamic table을 기본적으로 transient로 만들려면 dbt_project.yml에서 snowflake_default_transient_dynamic_tables 플래그를 활성화하세요.

예를 들어:

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='MY_WH',
    target_lag='1 hour',
    transient=true
) }}

select * from {{ source('raw', 'events') }}

Initialization warehouse

Snowflake는 dynamic table을 초기화하거나 재초기화할 때 사용할 가상 웨어하우스를 지정하는 INITIALIZATION_WAREHOUSE 파라미터를 지원해요. dbt-snowflake v1.12부터 snowflake_initialization_warehouse 파라미터로 이를 구성할 수 있어요. 이는 일반 incremental 새로고침에 쓰는 snowflake_warehouse 파라미터와 별개예요. snowflake_initialization_warehouse를 설정하면 초기 빌드·재초기화에는 더 큰 웨어하우스를, 일반 새로고침에는 snowflake_warehouse를 더 작게 유지할 수 있어요.

models/.sql

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='COMPUTE_WH',
    snowflake_initialization_warehouse='LARGE_WH',
    target_lag='1 minute'
) }}

select * from {{ source('raw', 'events') }}

핵심 사항:

  • snowflake_initialization_warehouse가 설정되지 않으면 Snowflake는 초기화와 일반 새로고침 둘 다에 snowflake_warehouse를 사용해요.
  • 기존 dynamic table에서 full refresh 없이 snowflake_initialization_warehouse를 바꿀 수 있어요.
  • 기본 동작으로 돌아가려면 모델 구성에서 snowflake_initialization_warehouse 파라미터를 제거하거나 명시적으로 None으로 설정하세요.

Snowflake 문서에서 INITIALIZATION_WAREHOUSE에 대해 더 알아보세요.

Limitations

대부분 데이터 플랫폼의 materialized view처럼 dynamic table에도 제한이 있어요. 주목할 만한 몇 가지:

  • Dynamic table SQL은 제한된 기능 세트를 가져요.
  • Dynamic table SQL은 갱신할 수 없어요. dynamic table은 --full-refresh(DROP/CREATE)를 거쳐야 해요.
  • Dynamic table은 다음의 다운스트림이 될 수 없어요: materialized views, external tables, streams.
  • Dynamic table은 다른 dynamic table의 다운스트림인 뷰를 참조할 수 없어요.

dynamic table 제한에 대한 더 많은 정보는 Snowflake 문서에서 찾을 수 있어요.

dbt 제한으로는 모델 contract가 지원되지 않아요.

Dynamic table 문제 해결

첫 실행 후 dynamic table 모델이 다음 오류로 재실행에 실패하면:

SnowflakeDynamicTableConfig.__init__() missing 6 required positional arguments: 'name', 'schema_name', 'database_name', 'query', 'target_lag', and 'snowflake_warehouse'

계정의 QUOTED_IDENTIFIERS_IGNORE_CASEFALSE로 설정되어 있는지 확인하세요.

Interactive tables Beta

dbt-snowflake v1.13부터 Snowflake 어댑터는 저지연 쿼리에 최적화된 interactive table을 지원해요. 이 materialization은 Snowflake 전용이라, dbt가 보통 view에 기본적으로 제공하는 모델 구성이 interactive table에는 적용되지 않을 수 있어요.

dbt의 interactive table 지원은 베타 — interactive table은 Snowflake에서 정식 출시됐지만, interactive_table materialization에 대한 dbt 지원은 v1과 v2 엔진 모두에서 베타예요. 동작과 구성 옵션이 바뀔 수 있어요.

  • dbt platform
  • dbt v2
  • dbt v1 (dbt-snowflake v1.13 이상에서 곧 제공)

target_lag을 설정하면 테이블이 Snowflake가 자동 새로고침하는 dynamic interactive table이 돼요. 설정하지 않으면 테이블은 static이고 dbt를 실행할 때만 다시 빌드돼요. 여러 구성은 어떤 형태를 쓰느냐에 따라 다르게 동작해요.

dynamic table처럼 interactive table도 on_configuration_change 설정에 접근할 수 있어요. Interactive table은 다음 구성 파라미터로 지원돼요.

dbt_project.yml

models:
  <resource-path>:
    +materialized: interactive_table
    +on_configuration_change: apply | continue | fail
    +cluster_by: <column-name> | [<column-name>, <column-name>, ...]
    +target_lag: <time-delta>
    +snowflake_warehouse: <warehouse-name>
    +refresh_warehouse: <warehouse-name>
    +snowflake_initialization_warehouse: <warehouse-name>

models/properties.yml

models:
  - name: [<model-name>]
    config:
      materialized: interactive_table
      on_configuration_change: apply | continue | fail
      cluster_by: <column-name> | [<column-name>, <column-name>, ...]
      target_lag: <time-delta>
      snowflake_warehouse: <warehouse-name>
      refresh_warehouse: <warehouse-name>
      snowflake_initialization_warehouse: <warehouse-name>

models/.sql

{{ config(
    materialized="interactive_table",
    on_configuration_change="apply" | "continue" | "fail",
    cluster_by="<column-name>" | ["<column-name>", "<column-name>", ...],
    target_lag="<integer> seconds | minutes | hours | days",
    snowflake_warehouse="<warehouse-name>",
    refresh_warehouse="<warehouse-name>",
    snowflake_initialization_warehouse="<warehouse-name>",

) }}

이 파라미터들에 대해 Snowflake 문서에서 더 알아보세요. 위 웨어하우스 파라미터는 DDL과 새로고침을 실행하는 일반 가상 웨어하우스를 말해요. 테이블을 interactive warehouse에 연결하지 않아요 — Limitations of interactive tables를 참고하세요.

Cluster by (interactive tables)

dynamic table에서 cluster_by가 선택 사항인 것과 달리, interactive table은 필수예요.

{{ config(
    materialized='interactive_table',
    cluster_by=['order_id'],
) }}

select * from {{ ref('stg_orders') }}

핵심 사항:

  • dbt는 프로젝트를 파싱할 때 cluster_by를 검증하므로, 값 생략, 빈 목록, 목록 내 빈 항목(예: ["id", " "])은 실행이 아니라 파싱 시 실패해요.
  • 기존 interactive table의 cluster_by를 바꾸면 full refresh가 트리거돼요.

클러스터링 컬럼 선택 지침은 Snowflake 문서의 CREATE INTERACTIVE TABLE을 참고하세요.

Target lag (interactive tables)

target_lag을 설정하면 테이블이 dynamic(자동 새로고침)이 돼요. Snowflake는 그 새로고침에 웨어하우스도 요구하므로, refresh_warehousesnowflake_warehouse 없이 target_lag을 설정하면 dbt가 파싱 시 오류를 냅니다.

{{ config(
    materialized='interactive_table',
    cluster_by=['order_id'],
    target_lag='30 minutes',
    snowflake_warehouse='MY_WH',
) }}

select * from {{ ref('stg_orders') }}

핵심 사항:

  • target_lag을 한 값에서 다른 값으로 바꾸면 alter 문으로 테이블을 제자리에서 갱신해요.
  • static 테이블에 target_lag을 추가하거나 dynamic 테이블에서 제거하면 테이블이 교체돼요. Snowflake는 alter로 static/dynamic 형태를 전환할 수 없어서, dbt는 create or replace를 실행해요. --full-refresh를 전달할 필요 없어요 — dbt가 알아서 해줘요.

Snowflake 문서의 CREATE INTERACTIVE TABLE에서 TARGET_LAG에 대해 더 알아보세요.

Refresh warehouse (interactive tables)

refresh_warehouse로 dynamic interactive table의 자동 새로고침을 dbt가 DDL 실행에 쓰는 웨어하우스(snowflake_warehouse)와 다른 웨어하우스에서 실행할 수 있어요. 새로고침에는 더 작은 웨어하우스를, DDL에는 더 큰 것을 유지할 수 있어요.

{{ config(
    materialized='interactive_table',
    cluster_by=['order_id'],
    target_lag='1 hour',
    snowflake_warehouse='LARGE_EXECUTION_WH',
    refresh_warehouse='SMALL_REFRESH_WH',
) }}

select * from {{ ref('stg_orders') }}

핵심 사항:

  • dynamic interactive table에서 refresh_warehouse가 설정되지 않으면 snowflake_warehouse가 DDL 실행과 자체 새로고침 둘 다에 쓰여요.
  • static interactive table에서 refresh_warehouse는 무시돼요. 테이블이 스스로 새로고침하지 않기 때문이에요. snowflake_warehouse는 dbt가 테이블을 빌드하는 웨어하우스를 계속 제어해요.
  • 기존 interactive table에서 full refresh 없이 refresh_warehouse를 바꿀 수 있어요.
  • dynamic interactive table에서 테이블을 교체하지 않고 refresh_warehouse를 바꿀 수 있어요. dbt는 alter 문으로 제자리에서 갱신해요.
  • 새로고침에 snowflake_warehouse를 다시 쓰려면 모델 구성에서 refresh_warehouse를 제거하세요.

Initialization warehouse (interactive tables)

dbt_semantic_view — dynamic interactive table을 초기화하거나 재초기화할 때 Snowflake가 사용할 가상 웨어하우스를 지정하려면 snowflake_initialization_warehouse를 쓰세요. 초기 빌드에는 더 큰 웨어하우스를, 일반 새로고침에는 snowflake_warehouse를 더 작게 유지할 수 있어요.

{{ config(
    materialized='interactive_table',
    cluster_by=['order_id'],
    target_lag='1 hour',
    snowflake_warehouse='COMPUTE_WH',
    snowflake_initialization_warehouse='LARGE_WH',
) }}

select * from {{ ref('stg_orders') }}

핵심 사항:

  • 이 파라미터는 테이블이 스스로 새로고침할 때만 적용돼요. static interactive table(target_lag 없음)에 설정하면 dbt는 무시하고 모델 실행 시 경고해요.
  • 기존 interactive table에서 full refresh 없이 snowflake_initialization_warehouse를 바꿀 수 있어요.
  • 기본 동작으로 돌아가려면 모델 구성에서 파라미터를 제거하거나 명시적으로 None으로 설정하세요.

Interactive table의 변경 모니터링

Interactive table은 on_configuration_change를 지원해요. Snowflake가 어떤 구성 변경을 제자리에서 적용할 수 있고 어떤 것이 전체 재빌드를 강제하는지 결정해요.

Interactive table의 지원되지 않는 구성

다음 구성은 interactive table에서 지원되지 않아요. dbt는 처음 두 개를 프로젝트 파싱 시 거부해, Snowflake가 실행을 실패시키도록 두지 않아요.

  • table_format: iceberg: interactive table에는 Iceberg 변형이 없어요.
  • transient: true: Snowflake는 transient interactive table을 받아들이지 않아요(오류 001003). dbt_project.yml에서 프로젝트 레벨로 transient: true를 설정하면 interactive table 모델이 이를 상속받아 실패해요. 그 모델들에 transient: false를 설정해 재정의하세요.
  • change_tracking: 허용되지만 무효(inert)예요. CREATE INTERACTIVE TABLE은 change tracking 옵션을 받지 않아요.

Interactive table의 제한

dbt로 interactive table을 빌드할 때 주목할 만한 제한:

  • dbt는 현재 interactive table을 interactive warehouse에 연결하거나 해제하지 않아요. 그 연결은 Snowflake에서 관리하세요. 이 둘은 독립 객체이며, Snowflake는 interactive warehouse를 다른 관계 타입에도 연결할 수 있어요.
  • interactive table에서 컬럼을 드롭하는 것은 지원되지 않아요. 이전에 interactive table이었던 관계에 대해 on_schema_change: sync_all_columns를 가진 incremental 모델을 실행하면 도달할 수 있어요.
  • interactive table을 incremental 모델로 변환하려면 --full-refresh가 필요해요.
  • interactive table은 클론하거나 개인 데이터베이스에 만들 수 없어요.
  • 모델 contract는 지원되지 않아요.

웨어하우스별 테이블 제한을 포함한 interactive table·interactive warehouse 제한에 대한 더 많은 정보는 Snowflake 문서에서 찾을 수 있어요.

Interactive table 문제 해결

table 모델 다운스트림의 dynamic interactive table이 오래된 데이터를 제공할 수 있음

dynamic interactive table이 dbt 관리 table 모델에서 읽으면, 그 업스트림 모델에서 dbt의 create or replace 문이 Snowflake의 change tracking 이력을 파괴해요. 그러면 interactive table이 더 이상 스스로 새로고침할 수 없지만, dbt run은 여전히 성공을 보고해요. 그래서 깨끗한 실행이 테이블이 오래된 행을 제공하게 둘 수 있어요.

복구하려면 interactive table을 --full-refresh로 실행하세요. 방지하려면 업스트림 모델에 change tracking을 다시 활성화하는 post-hook을 추가하세요.

{{ config(
    materialized='table',
    post_hook="alter table {{ this }} set change_tracking = true",
) }}

참고로 change_tracking 모델 config는 여기서 대체물이 아니에요. 그 config는 일반 table용 SQL에 도달하지 않기 때문이에요. 일반 dynamic table도 같은 노출이 있어요.

첫 실행 후 interactive table 모델이 누락된 위치 인자에 대한 오류로 재실행에 실패하면 계정의 QUOTED_IDENTIFIERS_IGNORE_CASEFALSE로 설정되어 있는지 확인하세요.

Semantic Views

Snowflake Semantic Views는 BI·분석 도구 전반에 걸쳐 메트릭 정의를 중앙화하고 단편화된 메트릭 로직을 줄이는 네이티브 스키마 레벨 객체를 제공해요.

dbt_semantic_view 패키지를 사용해 dbt 프로젝트에서 Snowflake Semantic Views를 정의하고 관리하세요. 이렇게 하면 Semantic View 정의를 버전 관리에 유지하고 기존 테스트·CI/CD 워크플로를 Semantic Layer에 적용할 수 있어요.

패키지 설치

전제 조건:

  • 이 패키지는 dbt 버전 >=1.0.0, dbt_semantic_view 패키지가 필요해요.
  • Snowflake 계정이 Semantic Views를 지원해요.
  • 롤에 Semantic Views를 만들 권한이 있어요.
  • create 권한이 있는 데이터베이스와 스키마에 쓸 수 있어요.

packages.yml 파일에 dbt_semantic_view를 추가하세요.

packages:
  - package: Snowflake-Labs/dbt_semantic_view
    version: 1.0.3

dbt deps를 실행해 패키지 의존성을 설치하세요.

dbt deps

dbt_packages/ 디렉터리에 dbt_semantic_view가 있는지 확인해 패키지가 설치됐는지 검증하세요.

주요 기능

dbt_semantic_view 패키지는 dbt 프로젝트에서 Snowflake Semantic Views를 정의·관리하는 다음 기능을 포함해요.

모델을 Snowflake Semantic Views로 materialize

semantic_view materialization을 사용해 tables, relationships, facts, dimensions, metrics를 포함한 Snowflake Semantic Views를 dbt에서 정의해요.

Semantic view 모델은 표준 SELECT 쿼리 대신 Snowflake의 semantic view 문법(예: TABLES, DIMENSIONS, METRICS)을 사용해요.

아래 예시는 Getting Started with Snowflake Semantic View에서 각색됐어요.

{{ config(materialized='semantic_view') }}

tables (
    CUSTOMER as {{ SOURCE('<SOURCE_NAME>', 'CUSTOMER') }} primary key (C_CUSTOMER_SK),
    DATE as {{ SOURCE('<SOURCE_NAME>', 'DATE_DIM') }} primary key (D_DATE_SK),
    DEMO as {{ SOURCE('<SOURCE_NAME>', 'CUSTOMER_DEMOGRAPHICS') }} primary key (CD_DEMO_SK),
    ITEM as {{ SOURCE('<SOURCE_NAME>', 'ITEM') }} primary key (I_ITEM_SK),
    STORE as {{ SOURCE('<SOURCE_NAME>', 'STORE') }} primary key (S_STORE_SK),
    STORESALES as {{ SOURCE('<SOURCE_NAME>', 'STORESALES') }}
    primary key (SS_SOLD_DATE_SK,SS_CDEMO_SK,SS_ITEM_SK,SS_STORE_SK,SS_CUSTOMER_SK)
)
relationships (
    SALESTOCUSTOMER as STORESALES(SS_CUSTOMER_SK) references CUSTOMER(C_CUSTOMER_SK),
    SALESTODATE as STORESALES(SS_SOLD_DATE_SK) references DATE(D_DATE_SK),
    SALESTODEMO as STORESALES(SS_CDEMO_SK) references DEMO(CD_DEMO_SK),
    SALESTOITEM as STORESALES(SS_ITEM_SK) references ITEM(I_ITEM_SK),
    SALETOSTORE as STORESALES(SS_STORE_SK) references STORE(S_STORE_SK)
)
facts (
    ITEM.COST as i_wholesale_cost,
    ITEM.PRICE as i_current_price,
    STORE.TAX_RATE as S_TAX_PERCENTAGE,
    STORESALES.SALES_QUANTITY as SS_QUANTITY
)
dimensions (
    CUSTOMER.BIRTHYEAR as C_BIRTH_YEAR,
    CUSTOMER.COUNTRY as C_BIRTH_COUNTRY,
    CUSTOMER.C_CUSTOMER_SK as c_customer_sk,
    DATE.DATE as D_DATE,
    DATE.D_DATE_SK as d_date_sk,
    DATE.MONTH as D_MOY,
    DATE.WEEK as D_WEEK_SEQ,
    DATE.YEAR as D_YEAR,
    DEMO.CD_DEMO_SK as cd_demo_sk,
    DEMO.CREDIT_RATING as CD_CREDIT_RATING,
    DEMO.MARITAL_STATUS as CD_MARITAL_STATUS,
    ITEM.BRAND as I_BRAND,
    ITEM.CATEGORY as I_CATEGORY,
    ITEM.CLASS as I_CLASS,
    ITEM.I_ITEM_SK as i_item_sk,
    STORE.MARKET as S_MARKET_ID,
    STORE.SQUAREFOOTAGE as S_FLOOR_SPACE,
    STORE.STATE as S_STATE,
    STORE.STORECOUNTRY as S_COUNTRY,
    STORE.S_STORE_SK as s_store_sk,
    STORESALES.SS_CDEMO_SK as ss_cdemo_sk,
    STORESALES.SS_CUSTOMER_SK as ss_customer_sk,
    STORESALES.SS_ITEM_SK as ss_item_sk,
    STORESALES.SS_SOLD_DATE_SK as ss_sold_date_sk,
    STORESALES.SS_STORE_SK as ss_store_sk
)
metrics (
    STORESALES.TOTALCOST as SUM(item.cost),
    STORESALES.TOTALSALESPRICE as SUM(SS_SALES_PRICE),
    STORESALES.TOTALSALESQUANTITY as SUM(SS_QUANTITY)
        WITH SYNONYMS = ('total sales quantity', 'total sales amount')
)

dbt를 실행하면 이 모델은 Snowflake CREATE SEMANTIC VIEW 문으로 컴파일돼요.

다른 dbt 모델에서 Semantic Views 참조

dbt 프로젝트에 정의된 Semantic Views에는 ref()를, 기존 외부 Semantic Views에는 source()를 사용하세요.

{{ config(materialized='view') }}

select * from semantic_view(
  {{ ref('<semantic_view_model_name>') }}
  METRICS ...
  DIMENSIONS ...
  WHERE ...
)
{{ config(materialized='table') }}

select * from semantic_view(
  {{ source('<source_name>', '<semantic_view>') }}
  METRICS ...
  DIMENSIONS ...
  WHERE ...
)

Temporary tables

컴파일 시간을 절약하고 temporary table이 시작하는 데이터베이스 쓰기 단계를 피하기 위해, Snowflake의 incremental table merge는 temporary table보다 view를 선호해요.

때로는 temporary table이 더 빠르거나 더 안전하게 결과를 얻을 수 있어요. tmp_relation_type 구성으로 incremental 빌드에 temporary 또는 transient table을 opt-in할 수 있어요. 이것은 모델 구성의 일부로 정의돼요.

정확성을 보장하려면 unique_key가 정의된 delete+insert 전략을 쓰는 incremental 모델은 temporary table이 필요해요. 이걸 view로 바꾸면 오류가 나요.

tmp_relation_type은 다음 값을 받아요.

  • view (기본값): tmp relation의 임시 물리 테이블 생성 중간 단계를 건너뛰어요. 가장 빠르지만 모든 전략에 적합하지 않아요.
  • table: 세션 범위의 temporary table. Snowflake 카탈로그에 보이지 않고 세션별로 격리돼요.
  • transient: transient table. 카탈로그에 남아 Snowflake 네이티브 lineage 추적을 가능하게 하면서, 영구 테이블의 7일 fail-safe 저장 비용은 피해요.

참고: 이 값은 나중에 설명할 별도의 모델 레벨 transient config(최종 모델 관계를 제어하는)와 구별돼요.

프로젝트 YAML에 정의:

dbt_project.yml

name: my_project

...

models:
  <resource-path>:
    +tmp_relation_type: table | view | transient ## If not defined, view is the default.

모델 SQL 파일 구성 형식:

dbt_model.sql

{{ config(
    tmp_relation_type="table | view | transient",
    -- If not defined, view is the default.
) }}

transient와의 동시 실행 충돌 — tmp_relation_typetransient로 설정하면 tmp relation은 결정적 이름으로 대상 스키마에 남는 실제 테이블이 돼요. 같은 incremental 모델의 여러 실행이 같은 스키마에서 동시에 실행되면 서로의 tmp relation을 덮어써 데이터 중복이나 잘못된 결과를 유발할 수 있어요. 예를 들어 개발자가 대상 스키마를 공유하거나 CI와 프로덕션 실행이 겹칠 때 이런 일이 생길 수 있어요.

이 위험은 dbt 모델의 스키마·데이터베이스를 어떻게 구성하느냐에 달려 있어요. 충돌을 막으려면 snowflake__resolve_incremental_tmp_relation을 사용해 tmp relation을 실행 또는 환경별로 고유한 스키마로 라우팅하세요. 자세한 내용은 Avoiding tmp relation conflicts를 참고하세요.

tmp relation 충돌 피하기

동시 실행 간 이름 충돌을 막으려면 snowflake__resolve_incremental_tmp_relation 디스패치 매크로를 재정의해 tmp relation을 전용 스키마로 리다이렉트하세요.

macros/snowflake_incremental.sql

{% macro snowflake__resolve_incremental_tmp_relation(tmp_relation) %}
  {{ return(tmp_relation.incorporate(schema='scratch')) }}
{% endmacro %}

이 매크로는 기본 tmp relation 객체를 받아 수정된 버전을 반환해요. 일반적인 재정의는 동시 실행 간 격리를 보장하기 위해 스키마에 개발자 username, CI job ID, 또는 target name을 추가하는 것 등이에요.

스키마에 target name을 추가하려면:

macros/snowflake_incremental.sql

{% macro snowflake__resolve_incremental_tmp_relation(tmp_relation) %}
  {%- set scratch_schema = target.schema ~ '_scratch_' ~ env_var('DBT_JOB_ID', target.name) -%}
  {{ return(tmp_relation.incorporate(schema=scratch_schema)) }}
{% endmacro %}

Transient tables

Snowflake는 transient table 생성을 지원해요. Snowflake는 이 테이블에 대한 이력을 보존하지 않아, Snowflake 저장 비용을 눈에 띄게 줄일 수 있어요. Transient table은 기본적으로 1일 보존 기간으로 제한된 정도로 time travel에 참여하고 fail-safe 기간은 없어요. dbt 모델을 transient로 구성할지 결정할 때 이런 트레이드오프를 저울질하세요. 기본적으로 dbt가 만드는 모든 Snowflake 테이블은 transient예요.

dbt_project.yml에서 transient table 구성

dbt_project.yml 파일에 한 줄을 추가하면 전체 폴더(또는 패키지)를 transient(또는 아니게)로 구성할 수 있어요. 이 config는 dbt_project.yml에 정의된 다른 모든 모델 config처럼 동작해요.

dbt_project.yml

name: my_project

...

models:
  +transient: false
  my_project:
    ...

특정 모델의 transience 구성

특정 모델은 transient 모델 config를 true로 설정해 transient로 구성할 수 있어요.

my_table.sql

{{ config(materialized='table', transient=true) }}

select * from ...

Query tags

Query tags는 나중에 QUERY_HISTORY 뷰에서 검색할 때 꽤 유용할 수 있는 Snowflake 파라미터예요.

dbt는 프로필에서 Snowflake 연결 기간 동안의 기본 query tag 설정을 지원해요. 모델 하위 집합에 대해 더 정확한 값(그리고 기본값 재정의)은 query_tag 모델 config를 설정하거나 기본 set_query_tag 매크로를 재정의해서 할 수 있어요.

dbt_project.yml

models:
  <resource-path>:
    +query_tag: dbt_special

models/.sql

{{ config(
    query_tag = 'dbt_special'
) }}

select ...

이 예시에서는 모델 이름으로 모든 쿼리에 적용되는 query tag를 설정할 수 있어요.

{% macro set_query_tag() -%}
  {% set new_query_tag = model.name %}
  {% if new_query_tag %}
    {% set original_query_tag = get_current_query_tag() %}
    {{ log("Setting query_tag to '" ~ new_query_tag ~ "'. Will reset to '" ~ original_query_tag ~ "' after materialization.") }}
    {% do run_query("alter session set query_tag = '{}'".format(new_query_tag)) %}
    {{ return(original_query_tag)}}
  {% endif %}
  {{ return(none)}}
{% endmacro %}

참고: query tags는 세션 레벨로 설정돼요. 각 모델 materialization 시작 시, 모델에 커스텀 query_tag가 설정되어 있으면 dbt는 alter session set query_tag를 실행해 새 값을 설정해요. materialization 끝에서 dbt는 태그를 기본값으로 되돌리는 또 다른 alter 문을 실행해요. 그래서 materialization 중간에 빌드가 실패하면 이후 쿼리가 잘못된 태그로 실행될 수 있어요.

Merge 동작 (incremental models)

incremental_strategy config는 dbt가 incremental 모델을 어떻게 빌드할지 제어해요. 기본적으로 dbt는 Snowflake에서 merge 문을 사용해 incremental 테이블을 새로고침해요.

Snowflake는 다음 incremental 전략을 지원해요.

  • merge (기본값)
  • append
  • delete+insert
  • insert_overwrite

참고: 이것은 표준 dbt incremental 전략이 아니에요. insert_overwrite는 Snowflake에서 truncate + 재insert 명령처럼 동작해요. 파티션 기반 덮어쓰기를 지원하지 않아, 의도적으로 전체 테이블을 덮어써요. 이는 기존 테이블을 drop하지 않는 dbt의 워크플로와 맞기 때문에 incremental 전략으로 구현됐어요. overwrite_columnsINSERT OVERWRITE 문에 포함할 컬럼을 제어할 수 있어요.

microbatch

Snowflake의 merge 문은 모델 config에 지정한 unique_key가 실제로 고유하지 않으면 "nondeterministic merge" 오류로 실패해요. 이 오류를 만나면 모델의 incremental_strategy config를 delete+insert로 설정해 dbt에 두 단계 incremental 접근을 사용하라고 지시할 수 있어요.

overwrite_columns

Snowflake에서 incremental_strategy='insert_overwrite'를 쓸 때 overwrite_columns를 설정해 dbt가 incremental 모델의 INSERT OVERWRITE 문을 어떻게 생성할지 제어할 수 있어요. 예:

models/my_model.sql

{{ config(
    materialized='incremental',
    incremental_strategy='insert_overwrite',
    overwrite_columns=['id', 'value', 'event_date']
) }}

select id, value, event_date
from {{ ref('my_source') }}
  • overwrite_columns를 설정하면 dbt는 INSERT 대상과 SELECT projection 양쪽에 컬럼을 명시적으로 나열하는 SQL을 생성해요.
insert overwrite into my_schema.my_table (id, value, event_date)
select id, value, event_date
from staging_table
  • overwrite_columns를 설정하지 않으면 dbt는 현재 SELECT *로 기본값을 써요.
insert overwrite into my_schema.my_table
select *
from staging_table

테이블 클러스터링 구성

dbt는 Snowflake의 테이블 클러스터링을 지원해요. 테이블이나 incremental 모델의 클러스터링을 제어하려면 cluster_by config를 쓰세요. 이 구성이 적용되면 dbt는 두 가지를 해요.

  1. 지정된 cluster_by 필드로 테이블 결과를 암시적으로 정렬해요.
  2. 대상 테이블에 지정된 클러스터링 키를 추가해요.

지정된 cluster_by 필드로 테이블을 정렬하면 dbt는 Snowflake의 자동 클러스터링이 해야 할 작업을 최소화해요. incremental 모델이 테이블 클러스터링을 쓰도록 구성되면, dbt는 대상 테이블에 병합하기 전에 스테이지된 데이터셋도 정렬해요. 그래서 dbt 관리 테이블은 항상 대부분 클러스터된 상태를 유지해야 해요.

cluster_by 사용

cluster_by config는 문자열 또는 클러스터링 키로 쓸 문자열 목록을 받아요. 다음 예시는 session_start 컬럼으로 클러스터된 sessions 테이블을 만들어요.

models/events/sessions.sql

{{
  config(
    materialized='table',
    cluster_by=['session_start']
  )
}}

select
  session_id,
  min(event_time) as session_start,
  max(event_time) as session_end,
  count(*) as count_pageviews

from {{ source('snowplow', 'event') }}
group by 1

위 코드는 (대략) 이렇게 생긴 SQL로 컴파일돼요.

create or replace table my_database.my_schema.my_table as (

  select * from (
    select
      session_id,
      min(event_time) as session_start,
      max(event_time) as session_end,
      count(*) as count_pageviews

    from {{ source('snowplow', 'event') }}
    group by 1
  )

  -- this order by is added by dbt in order to create the
  -- table in an already-clustered manner.
  order by session_start

);

 alter table my_database.my_schema.my_table cluster by (session_start);

Dynamic table 클러스터링

dbt v1.11부터 dynamic table은 cluster_by 구성을 지원해요. 설정하면 dbt가 CREATE DYNAMIC TABLE 문에 클러스터링 사양을 포함해요.

예를 들어:

{{ config(
    materialized='dynamic_table',
    snowflake_warehouse='COMPUTE_WH',
    target_lag='1 minute',
    cluster_by=['session_start', 'user_id']
) }}

select
    session_id,
    user_id,
    min(event_time) as session_start,
    max(event_time) as session_end,
    count(*) as count_pageviews
from {{ source('snowplow', 'event') }}
group by 1, 2

이 config는 컴파일되면 다음 SQL을 생성해요.

create or replace dynamic table my_database.my_schema.my_table
  target_lag = '1 minute'
  warehouse = COMPUTE_WH
  cluster by (session_start, user_id)
as (
  select
    session_id,
    user_id,
    min(event_time) as session_start,
    max(event_time) as session_end,
    count(*) as count_pageviews
  from source_table
  group by 1, 2
);

CREATE DYNAMIC TABLE 문에서 CLUSTER BY로 생성 시 dynamic table의 클러스터링을 지정할 수 있어요. 별도의 ALTER TABLE 문을 실행할 필요 없어요.

자동 클러스터링

자동 클러스터링은 현재 Snowflake에서 기본적으로 활성화되어 있어서, 사용하기 위해 어떤 조치도 필요 없어요. automatic_clustering config가 있지만, (더 이상 사용되지 않는) 수동 클러스터링이 활성화된 계정을 제외하고는 효과가 없어요.

계정에 수동 클러스터링이 여전히 활성화되어 있다면, automatic_clustering config로 dbt 모델의 자동 클러스터링 활성화 여부를 제어할 수 있어요. automatic_clusteringtrue로 설정하면 dbt는 대상 테이블을 만든 뒤 alter table resume recluster 쿼리를 실행해요.

automatic_clustering config는 dbt_project.yml 파일이나 모델 config() 블록에서 지정할 수 있어요.

dbt_project.yml

models:
  +automatic_clustering: true

Python 모델 구성

Snowflake 어댑터는 Python 모델을 지원해요. Snowflake는 자체 프레임워크인 Snowpark를 사용하는데, PySpark와 유사점이 많아요.

추가 설정: Anaconda 패키지를 쓰려면 Snowflake Third Party Terms를 인지하고 수락해야 해요.

패키지 설치: Snowpark는 Anaconda를 통해 여러 인기 패키지를 지원해요. 자세한 내용은 전체 목록을 참고하세요. 패키지는 모델이 실행될 때 설치돼요. 모델마다 패키지 의존성이 다를 수 있어요. 써드파티 패키지를 쓰면 Snowflake는 동시 사용자가 많은 웨어하우스보다 전용 가상 웨어하우스를 써서 최고 성능을 얻는 것을 권장해요.

Python 버전: 다른 Python 버전을 지정하려면 다음 구성을 사용하세요.

def model(dbt, session):
    dbt.config(
        materialized = "table",
        python_version="3.11"
    )

python_version config로 Snowpark 모델을 Python 3.9, 3.10, 3.11로 실행할 수 있어요.

외부 접근 통합과 비밀(secrets): dbt Python 모델 내에서 외부 API를 쿼리하려면 Snowflake의 external access와 함께 secrets를 사용하세요. 사용할 수 있는 추가 구성은 다음과 같아요.

import pandas
import snowflake.snowpark as snowpark

def model(dbt, session: snowpark.Session):
    dbt.config(
        materialized="table",
        secrets={"secret_variable_name": "test_secret"},
        external_access_integrations=["test_external_access_integration"],
    )
    import _snowflake
    return session.create_dataframe(
        pandas.DataFrame(
            [{"secret_value": _snowflake.get_generic_secret_string('secret_variable_name')}]
        )
    )

Docs: "Developer Guide: Snowpark Python"

써드파티 Snowflake 패키지

Snowflake Anaconda에 없는 써드파티 Snowflake 패키지를 쓰려면, 이 예시를 따라 패키지를 업로드한 뒤 dbt Python 모델의 imports 설정으로 Snowflake staging의 zip 파일을 참조하세요.

zip 파일을 사용한 완전한 예시 구성(파일을 다룸):

def model(dbt, session):
    # Configure the model
    dbt.config(
        materialized="table",
        imports=["@mystage/mycustompackage.zip"],  # Specify the external package location
    )

    # Example data transformation using the imported package
    # (Assuming `some_external_package` has a function we can call)
    data = {
        "name": ["Alice", "Bob", "Charlie"],
        "score": [85, 90, 88]
    }
    df = pd.DataFrame(data)

    # Process data with the external package
    df["adjusted_score"] = df["score"].apply(lambda x: some_external_package.adjust_score(x))

    # Return the DataFrame as the model output
    return df

이 구성 사용에 대한 자세한 내용은 Snowflake Anaconda 채널에 게시되지 않은 다른 Python 패키지를 Snowpark에서 업로드하고 사용하는 방법에 대한 Snowflake 문서를 참고하세요.

가상 웨어하우스 구성

dbt가 사용하는 기본 웨어하우스는 Snowflake 연결용 프로필에서 구성할 수 있어요. 특정 모델(또는 모델 그룹)에 사용되는 웨어하우스를 재정의하려면 snowflake_warehouse 모델 구성을 쓰세요. 이 구성은 특정 모델에 더 큰 웨어하우스를 지정해 Snowflake 비용과 프로젝트 빌드 시간을 제어하는 데 쓸 수 있어요.

테스트도 snowflake_warehouse 구성을 지원해요. 모델을 만드는 데 쓴 것과 다른 Snowflake 가상 웨어하우스에서 테스트를 실행하고 싶을 때(예: 가벼운 데이터 테스트에 더 작은 웨어하우스, 모델은 더 큰 웨어하우스) 유용해요.

다음 예시는 YAML의 config 인자로 모델 그룹의 웨어하우스를 바꿔요.

dbt_project.yml

name: my_project
version: 1.0.0

...

models:
  +snowflake_warehouse: "EXTRA_SMALL"    # default Snowflake virtual warehouse for all models in the project.
  my_project:
    clickstream:
      +snowflake_warehouse: "EXTRA_LARGE"    # override the default Snowflake virtual warehouse for all models under the `clickstream` directory.
snapshots:
  +snowflake_warehouse: "EXTRA_LARGE"    # all Snapshot models are configured to use the `EXTRA_LARGE` warehouse.
data_tests:
  +snowflake_warehouse: "EXTRA_SMALL"    # all data tests are configured to use the `EXTRA_SMALL` warehouse.

다음 예시는 property 파일의 config 인자로 단일 모델과 특정 테스트의 Snowflake 웨어하우스를 재정의해요.

models/my_model.yml

models:
  - name: my_model
    config:
      snowflake_warehouse: "EXTRA_LARGE"    # override the Snowflake virtual warehouse just for this model
    columns:
      - name: id
        data_tests:
          - unique:
              config:
                snowflake_warehouse: "EXTRA_SMALL"    # use a smaller warehouse for this test

다음 예시는 SQL 모델의 config() 블록으로 단일 모델의 웨어하우스를 바꿔요.

models/events/sessions.sql

# override the Snowflake virtual warehouse for just this model
{{
  config(
    materialized='table',
    snowflake_warehouse='EXTRA_LARGE'
  )
}}

with

aggregated_page_events as (

    select
        session_id,
        min(event_time) as session_start,
        max(event_time) as session_end,
        count(*) as count_page_views
    from {{ source('snowplow', 'event') }}
    group by 1

),

index_sessions as (

    select
        *,
        row_number() over (
            partition by session_id
            order by session_start
        ) as page_view_in_session_index
    from aggregated_page_events

)

select * from index_sessions

Copying grants

copy_grants config를 true로 설정하면 dbt는 테이블, 뷰, dynamic table(dbt-snowflake v1.11 이상)을 다시 빌드할 때 copy grants DDL 수식어를 추가해요. 기본값은 false예요.

dbt_project.yml

models:
  +copy_grants: true

(dbt v1.10 이상 적용)

행 접근 정책 설정

모델의 row_access_policy config로 테이블, 뷰, dynamic table에 행 접근 정책을 구성해요. 정책은 모델에 적용하기 전에 Snowflake에 이미 존재해야 해요.

models/.sql

{{ config(
    row_access_policy = 'my_database.my_schema.my_row_access_policy_name on (id)'
) }}

select ...

테이블 태그 구성

테이블, 뷰, dynamic table에 태그를 추가하려면 table_tag config를 쓰세요. 참고로 태그는 적용 전에 Snowflake에 이미 존재해야 해요.

models/.sql

{{ config(
    table_tag = "my_tag_name = 'my_tag_value'"
) }}

select ...

Secure views

Snowflake secure view를 만들려면 view 모델에 secure config를 쓰세요. Secure view는 민감 데이터에 대한 접근을 제한하는 데 쓸 수 있어요. 참고: secure view는 성능 저하가 있을 수 있으므로 필요할 때만 써야 해요.

다음 예시는 sensitive/ 폴더의 모델을 secure view로 구성해요.

dbt_project.yml

name: my_project
version: 1.0.0

models:
  my_project:
    sensitive:
      +materialized: view
      +secure: true

Source freshness 알려진 제한

Snowflake는 LAST_ALTERED 컬럼의 정보를 사용해 source freshness를 계산해요. 즉 데이터 갱신뿐 아니라 객체에 어떤 수정이든 발생할 때 갱신되는 필드에 의존한다는 뜻이에요. 조치할 것은 없지만, 분석 팀은 이 주의 사항을 알아야 해요.

Snowflake 문서에 따르면:

LAST_ALTERED 컬럼은 객체에 다음 작업이 수행될 때 갱신돼요.

  • DDL 작업.
  • DML 작업 (테이블만).
  • Snowflake가 수행하는 메타데이터의 백그라운드 유지보수 작업.

(dbt v1.9 이상 적용)

객체 결과 페이징

기본적으로 dbt가 최대 100,000개 객체가 있는 스키마를 만나면, show objects 결과를 페이지당 10,000개씩 최대 10페이지로 페이징해요. 스키마에 객체가 100,000개를 넘는 환경은 dbt_project.yml에서 다음 플래그로 페이지당 결과 수와 페이지 제한을 커스터마이즈할 수 있어요.

  • list_relations_per_page — 각 페이지의 관계 수 (Snowflake가 허용하는 최대가 10k이므로 최대 10k).
  • list_relations_page_limit — 결과에 포함할 최대 페이지 수.

예를 들어 페이지당 10,000개 객체를 포함하고 최대 100페이지(100만 객체)를 포함하려면 플래그를 다음과 같이 구성하세요.

flags:
  list_relations_per_page: 10000
  list_relations_page_limit: 100

더 알아보기 (Learn more)