Databricks 구성

Databricks 구성 (Databricks configurations)

이 문서는 dbt-databricks 플러그인에서 모델에 적용할 수 있는 다양한 리소스 구성을 설명해요. 테이블 구성, Python 제출 방법, 컬럼 구성, 행 필터, 점진적 전략(append, insert_overwrite, merge, replace_where, delete+insert, microbatch), 쿼리 태그, 구체화된 뷰와 스트리밍 테이블, 메트릭 뷰 등 Databricks만의 강력한 기능들을 강사 목소리로 차근차근 살펴볼게요.

출처: 문서

본문

테이블 구성하기

모델을 table로 구체화할 때, 표준 모델 구성 외에도 dbt-databricks 플러그인 특유의 몇 가지 선택적 구성을 포함할 수 있어요.

dbt-databricks v1.9는 table_format: iceberg 구성을 지원합니다. dbt v1 최신 릴리스 트랙에서 지금 사용해 볼 수 있어요. 다른 모든 테이블 구성도 1.8에서 지원되었습니다.

옵션 설명 필수? 모델 지원 예시
table_format materialization에 Iceberg 호환성을 제공할지 여부 선택 SQL, Python iceberg
use_uniform ¹ table_formaticeberg일 때 dbt가 Unity Catalog 관리 Iceberg 테이블(false)을 만들지, Iceberg 읽기가 활성화된 UniForm Delta 테이블(true)을 만들지 제어합니다. Databricks Iceberg 지원을 참고하세요. 선택 SQL, Python true
file_format ² 테이블 생성 시 사용할 파일 형식(parquet, delta, hudi, csv, json, text, jdbc, orc, hive 또는 libsvm). 선택 SQL, Python delta
location_root 생성된 테이블이 데이터를 저장할 디렉터리를 지정합니다. 테이블 별칭이 뒤에 추가됩니다. 선택 SQL, Python /mnt/root
include_full_name_in_path location root를 지정할 때 전체 테이블 경로를 사용할지 여부. 설정하면 database, schema, table 별칭이 모두 location root에 추가됩니다. 선택 SQL, Python true
partition_by 생성된 테이블을 지정된 컬럼으로 파티셔닝합니다. 파티션마다 디렉터리가 만들어집니다. 선택 SQL, Python date_day
liquid_clustered_by ³ 생성된 테이블을 지정된 컬럼으로 클러스터링합니다. 클러스터링 방식은 Delta의 Liquid Clustering 기능을 기반으로 합니다. dbt-databricks 1.6.2부터 사용 가능. 선택 SQL, Python date_day
auto_liquid_cluster ⁴ 생성된 테이블이 Databricks에 의해 자동으로 클러스터링됩니다. dbt-databricks 1.10.0부터 사용 가능. 선택 SQL, Python auto_liquid_cluster: true
clustered_by 생성된 테이블의 각 파티션을 지정된 컬럼으로 고정된 수의 버킷으로 나눕니다. 선택 SQL, Python country_code
buckets 클러스터링 중 만들 버킷 수. clustered_by가 지정되면 필수입니다. clustered_by 지정 시 필수 SQL, Python 8
tblproperties 생성된 테이블에 설정할 Tblproperties 선택 SQL, Python ⁵ {'this.is.my.key': 12}
databricks_tags 생성된 테이블에 설정할 태그 선택 SQL ⁶, Python ⁶ {'my_tag': 'my_value'}
compression 압축 알고리즘 설정. 선택 SQL, Python zstd
skip_optimize ⁷ 테이블 정의에 zorder / liquid_clustered_by / auto_liquid_cluster를 유지하면서 이 모델의 구체화 후 OPTIMIZE 작업을 건너뜁니다. dbt-databricks 1.12.2부터 사용 가능. 선택 SQL, Python skip_optimize: true

¹ use_uniformdbt v2에만 적용됩니다. dbt-databricks는 아직 이 구성을 지원하지 않아 어댑터가 경고를 기록하고 값을 무시합니다. dbt-databricks에서는 대신 use_managed_iceberg 동작 플래그를 사용하세요. ² table_formaticebergfile_format은 반드시 delta여야 합니다. 이 요구사항은 dbt-databricks에만 적용됩니다. dbt v2에서는 관리 Iceberg 테이블이 parquet을 사용합니다. ³ liquid_clustered_by를 활성화하면 dbt-databricks는 각 실행 후 OPTIMIZE(Liquid Clustering) 작업을 실행합니다. 이를 비활성화하려면 DATABRICKS_SKIP_OPTIMIZE=true 변수를 설정하세요. 이 변수는 dbt run 명령(dbt run --vars "{'databricks_skip_optimize': true}")으로 전달하거나 환경 변수로 설정할 수 있습니다. 이슈 #802를 참고하세요. ⁴ 같은 모델에서 liquid_clustered_byauto_liquid_cluster를 함께 사용하지 마세요. ⁵ 테이블 생성 시 tblproperties를 설정할 PySpark API가 아직 없어서, 이 기능은 주로 Python 파생 테이블에 tblproperties를 주석으로 달기 위한 것입니다. ⁶ databricks_tagsALTER 문으로 적용됩니다. 적용된 태그는 dbt-databricks로는 제거할 수 없어요. 태그를 제거하려면 Databricks를 직접 사용하거나 post-hook을 사용하세요. dbt-databricks v1.12부터 여러 구성 계층 수준에서 설정된 databricks_tags는 낮은(더 구체적인) 수준이 높은 수준을 완전히 대체하는 대신 가산적으로 병합됩니다. ⁷ skip_optimize는 구체화 후 OPTIMIZE 호출을 모델별로 제어합니다. 표준 dbt 모델 구성이므로 구성 상속을 통해 폴더나 프로젝트 수준에서도 설정할 수 있어요. 실행 범위 전체의 DATABRICKS_SKIP_OPTIMIZE 변수가 skip_optimize보다 우선합니다. DATABRICKS_SKIP_OPTIMIZE=true(또는 databricks_skip_optimize: true)를 설정하면 변수가 모든 모델의 OPTIMIZE를 건너뛰며, 개별 모델에서 skip_optimize: false로 다시 활성화할 수 없습니다. 대부분의 모델에서 OPTIMIZE를 켜두고 특정 모델만 제외하려면 skip_optimize를 사용하세요 — 예를 들어 OPTIMIZE를 Predictive Optimization에 위임하거나 대역 외로 예약할 때요. 이슈 #703을 참고하세요.

dbt-databricks v1.10에는 use_materialization_v2 플래그 뒤에 숨겨진 몇 가지 새로운 모델 구성 옵션이 있어요. 자세한 내용은 Databricks 동작 플래그 문서를 참고하세요.

Python 제출 방법

버전 1.9 이상에서 사용 가능

dbt-databricks v1.9(현재 최신 릴리스 트랙에서 사용 가능)에서는 submission_method에 다음 네 가지 옵션을 사용할 수 있어요.

  • all_purpose_cluster: Python 모델을 command api로 직접 실행하거나, 노트북을 업로드하고 일회성 작업 실행을 만들어 실행합니다.
  • job_cluster: 새 작업 클러스터를 만들어 업로드한 노트북을 일회성 작업 실행으로 실행합니다.
  • serverless_cluster: serverless cluster를 사용해 업로드한 노트북을 일회성 작업 실행으로 실행합니다.
  • workflow_job: 재사용 가능한 워크플로와 업로드한 노트북을 만들거나 업데이트해, all-purpose/job/serverless 클러스터에서 실행합니다.

주의: 이 방식은 최대 유연성을 제공하지만 Databricks에 지속적인 아티팩트(워크플로)를 생성하므로, 사용자가 dbt 밖에서 실행할 수도 있습니다.

현재는 옛 제출 방식(컴퓨팅별로 그룹화됨)과 논리적으로 구분된 제출 방식(command, job run, workflow) 사이에 불일치가 있는 전환기에 있습니다. 따라서 지원 구성 매트릭스가 다소 복잡합니다.

구성 용도 기본값 all_purpose_cluster job_cluster serverless_cluster workflow_job
create_notebook false면 Command API를 사용하고, 그렇지 않으면 노트북을 업로드해 job run 사용 false
timeout command/job이 실행되기를 기다리는 최대 시간 0 (제한 없음)
job_cluster_config 모델 실행용 새 클러스터 구성 {}
access_control_list job의 접근 제어를 직접 구성 {}
packages 실행 클러스터에 설치할 패키지 목록 []
index_url 패키지를 설치할 URL None (pypi 사용)
additional_libs 라이브러리를 직접 구성 []
python_job_config jobs/workflows용 추가 구성 (아래 표 참고) {}
cluster_id 실행할 기존 all purpose cluster의 id None
http_path 실행할 기존 all purpose cluster의 경로 None
  • create_notebook이 false일 때는 timeoutcluster_id/http_path만 지원됩니다.

workflow_job 제출 방법의 도입과 함께, Python 모델 제출의 추가 구성을 python_job_config라는 최상위 구성 아래로 세분화하기로 했어요. 이렇게 하면 job과 workflow 구성 옵션을 다른 모델 구성과 간섭하지 않도록 네임스페이스로 격리해, job 실행에 지원되는 것을 훨씬 유연하게 만들 수 있습니다.

이 기능의 지원 매트릭스는 workflow_job과 그 외 전부(create_notebook==true인 all_purpose_cluster 가정)로 나뉩니다. 나열된 각 구성 옵션은 반드시 python_job_config 아래에 중첩되어야 해요.

구성 용도 기본값 workflow_job 그 외 전부
name 생성한(또는 찾는 데 사용하는) 워크플로의 이름 None
grants 워크플로의 접근 제어를 지정하는 간단한 방식 {}
existing_job_id 생성한 워크플로를 찾는 데 사용할 Id(name 대신) None
post_hook_tasks 모델 노트북 실행 후 포함할 작업 []
additional_task_settings 모델 작업에 포함할 추가 작업 구성 {}
기타 job run 설정 요청에 모델 작업 밖에 복사될 구성 None
기타 workflow 설정 요청에 모델 작업 밖에 복사될 구성 None

이 예시는 이전 표의 새 구성 옵션을 사용합니다.

schema.yml:

models:
  - name: my_model
    config:
      submission_method: workflow_job
      # 이 워크플로 실행용 job cluster를 생성하려면 정의
      # 또는 cluster_id를 지정해 기존 클러스터를 사용하거나, 어느 것도 제공하지 않으면 serverless cluster 사용
      job_cluster_config:
        spark_version: "15.3.x-scala2.12"
        node_type_id: "rd-fleet.2xlarge"
        runtime_engine: "{{ var('job_cluster_defaults.runtime_engine') }}"
        data_security_mode: "{{ var('job_cluster_defaults.data_security_mode') }}"
        autoscale: {
          "min_workers": 1,
          "max_workers": 4
        }
      python_job_config:
        # 이 설정들은 그대로 요청에 전달됨
        email_notifications: {
          on_failure: ["[email protected]"]
        }
        max_retries: 2
        name: my_workflow_name
        # 모델의 dbt 작업에 대한 설정을 덮어씀. 예를 들어 작업 key를 변경할 수 있음
        additional_task_settings: {
          "task_key": "my_dbt_task"
        }
        # 모델 전후로 실행할 작업 정의
        # 이 예시는 /my_notebook_path에 optimize와 vacuum을 수행할 노트북을 이미 업로드했다고 가정
        post_hook_tasks: [
          {
            "depends_on": [
              { "task_key": "my_dbt_task" }
            ],
            "task_key": "OPTIMIZE_AND_VACUUM",
            "notebook_task": {
              "notebook_path": "/my_notebook_path",
              "source": "WORKSPACE"
            },
          },
        ]
        # 각 사용자별 권한을 따로 지정하는 대신 단순화된 구조
        grants:
          view: [
            { "group_name": "marketing-team" }
          ]
          run: [
            { "user_name": "[email protected]" }
          ]
          manage: [ ]

컬럼 구성하기

버전 1.10 이상에서 사용 가능

다양한 유형의 모델을 구체화할 때, 표준 컬럼 구성 외에도 dbt-databricks 플러그인 특유의 몇 가지 선택적 컬럼 수준 구성을 포함할 수 있어요. 컬럼 태그와 컬럼 마스크 지원은 dbt-databricks v1.10.4에 추가되었습니다.

옵션 설명 필수? 모델 지원 구체화 지원 예시
databricks_tags 개별 컬럼에 설정할 태그 선택 SQL†, Python† Table, Incremental, Materialized View, Streaming Table {'data_classification': 'pii'}
column_mask 동적 데이터 마스킹을 위한 컬럼 마스크 구성. function 및 선택적 using_columns 속성*을 허용 선택 SQL, Python Table, Incremental, Streaming Table {'function': 'my_catalog.my_schema.mask_email'}
  • using_columnsDatabricks 컬럼 마스크 파라미터에 나열된 모든 파라미터 유형을 지원합니다. † databricks_tagsALTER 문으로 적용됩니다. 적용된 태그는 dbt-databricks로는 제거할 수 없어요. 태그를 제거하려면 Databricks를 직접 사용하거나 post-hook을 사용하세요. dbt-databricks v1.12부터 여러 구성 계층 수준에서 설정된 databricks_tags는 낮은 수준이 높은 수준을 완전히 대체하는 대신 가산적으로 병합됩니다.

이 예시는 이전 표의 컬럼 수준 구성을 사용합니다.

schema.yml:

models:
  - name: customers
    columns:
      - name: customer_id
        databricks_tags:
          data_classification: "public"
      - name: email
        databricks_tags:
          data_classification: "pii"
        column_mask:
          function: my_catalog.my_schema.mask_email
          using_columns: "customer_id, 'literal string'"

행 필터 설정하기

버전 1.12 이상에서 사용 가능

row_filter를 설정해 모델에 Unity Catalog 행 필터를 적용할 수 있어요. 이는 SQL UDF를 기반으로 쿼리가 반환하는 행을 제한합니다. dbt는 관계를 만들 때 WITH ROW FILTER 절로 필터를 적용하고, 이후 실행에서는 ALTER ... SET ROW FILTER/ALTER ... DROP ROW FILTER를 내보내 필터를 추가·업데이트·제거합니다.

row_filter는 선택적 모델 수준 구성입니다. 설정하면 다음 두 속성이 모두 필요합니다.

속성 설명 필수? 예시
function 적용할 행 필터 UDF. 비정규화 이름(모델의 catalog와 schema로 dbt가 정규화) 또는 완전히 정규화된 catalog.schema.function을 제공하세요. 두 부분으로 된 schema.function 이름은 모호해서 dbt가 거부합니다. region_filter
columns 필터 함수의 인자로 전달되는 컬럼. 단일 문자열 또는 목록일 수 있습니다. function이 설정되면 필요. [region]

행 필터는 table, incremental, materialized_view, streaming_table 구체화에서 지원됩니다. 일반 뷰나 Hive Metastore 관계에서는 지원되지 않으며, 여기에 row_filter를 구성하면 컴파일러 오류가 발생합니다.

이 예시는 모델에 행 필터를 적용합니다.

schema.yml:

models:
  - name: orders
    config:
      row_filter:
        function: my_catalog.my_schema.region_filter
        columns: [region]

점진적 모델

버전 1.9 이상에서 사용 가능

v1.11.0의 파괴적 변경 dbt-databricks v1.11.0은 점진적 모델에 Databricks Runtime 12.2 LTS 이상을 요구합니다. 이 버전은 Databricks의 INSERT BY NAME 구문(DBR 12.2부터 사용 가능)을 사용해 점진적 모델의 컬럼 순서 불일치에 대한 수정을 도입합니다. 이는 on_schema_change: sync_all_columns를 사용하는 모델에서 컬럼 순서가 변경될 때 발생할 수 있는 데이터 손상을 방지합니다.

이전 런타임을 사용한다면:

  • dbt-databricks 버전을 1.10.x로 고정하거나
  • DBR 12.2 LTS 이상으로 업그레이드하세요.

이 파괴적 변경은 모든 점진적 전략(append, insert_overwrite, replace_where, delete+insert, merge(중간 테이블 생성 포함))에 영향을 줍니다. v1.11.0 변경에 대한 자세한 내용은 dbt-databricks v1.11.0 변경 로그를 참고하세요.

dbt-databricks 플러그인은 incremental_strategy 구성을 크게 활용합니다. 이 구성은 점진적 materialization이 첫 실행 이후의 실행에서 모델을 어떻게 만들지 알려줍니다. 다음 여섯 가지 값 중 하나로 설정할 수 있어요.

  • append: 기존 데이터를 업데이트하거나 덮어쓰지 않고 새 레코드를 삽입합니다.
  • insert_overwrite: partition_by가 지정되면 table의 파티션을 새 데이터로 덮어씁니다. partition_by가 지정되지 않으면 전체 테이블을 새 데이터로 덮어씁니다.
  • merge(기본값; Delta 및 Hudi 파일 형식 전용): unique_key를 기준으로 레코드를 매칭해 기존 레코드를 업데이트하고 새 레코드를 삽입합니다. (unique_key가 지정되지 않으면 append와 유사하게 모든 새 데이터가 삽입됩니다.)
  • replace_where(Delta 파일 형식 전용): incremental_predicates를 기준으로 레코드를 매칭해, 기존 테이블에서 조건과 일치하는 모든 레코드를 새 데이터에서 조건과 일치하는 레코드로 교체합니다. (incremental_predicates가 지정되지 않으면 append와 유사하게 모든 새 데이터가 삽입됩니다.)
  • delete+insert(Delta 파일 형식 전용, v1.11+에서 사용 가능): 필수 unique_key를 기준으로 레코드를 매칭해 일치하는 레코드를 삭제하고 새 레코드를 삽입합니다. 선택적으로 incremental_predicates로 필터링할 수 있어요.
  • microbatch(Delta 파일 형식 전용): event_time을 기반으로 생성된 조건과 함께 replace_where를 사용해 microbatch 전략을 구현합니다.

각 전략에는 장단점이 있으며 아래에서 다루겠습니다. 다른 모델 구성과 마찬가지로 incremental_strategydbt_project.yml이나 모델 파일의 config() 블록 안에 지정할 수 있어요.

append 전략

append 전략을 따르면 dbt가 모든 새 데이터로 insert into 문을 수행합니다. 이 전략의 장점은 모든 플랫폼, 파일 유형, 연결 방법, Apache Spark 버전에서 간단하고 기능한다는 점입니다. 그러나 이 전략은 기존 데이터를 업데이트·덮어쓰기·삭제할 수 없으므로, 많은 데이터 소스에 중복 레코드가 삽입될 가능성이 있습니다.

원본 코드 (databricks_incremental.sql):

{{ config(
  materialized = 'incremental',
  incremental_strategy = 'append',
) }}
--  이 쿼리가 반환하는 모든 행은 기존 테이블에 추가됩니다
select * from {{ ref('events') }}
{% if is_incremental() %}
where event_ts > (select max(event_ts) from {{ this }})
{% endif %}

컴파일된 코드 (databricks_incremental.sql):

create temporary view databricks_incremental__dbt_tmp as
select * from analytics.events
where event_ts >= (select max(event_ts) from {{ this }});
insert into table analytics.databricks_incremental
select `date_day`, `users` from databricks_incremental__dbt_tmp

insert_overwrite 전략

insert_overwrite 전략은 새 레코드만 추가하는 대신 기존 레코드를 교체해 테이블의 데이터를 업데이트합니다. 이 전략은 모델 구성의 partition_by 또는 liquid_clustered_by 절과 함께 지정할 때 가장 효과적이며, 쿼리가 영향을 주는 특정 파티션이나 클러스터를 식별하는 데 도움이 됩니다. dbt는 전체 테이블을 다시 만드는 대신 쿼리에 포함된 모든 파티션/클러스터를 동적으로 교체하는 atomic insert into ... replace on 문을 실행합니다.

중요! 이 점진적 전략을 사용할 때는 파티션이나 클러스터의 모든 관련 데이터를 다시 선택하세요. liquid_clustered_by를 사용할 때는 교체에 사용되는 replace on 키가 liquid_clustered_by 키와 동일합니다(partition_by 동작과 동일). use_replace_on_for_insert_overwritetrue로 설정하면(SQL 웨어하우스 또는 클러스터 컴퓨팅 사용 시) dbt는 파티션을 동적으로 덮어쓰고 모델 쿼리가 반환하는 파티션이나 클러스터만 교체합니다. dbt는 partitionOverwriteMode='dynamic' insert overwrite 문을 실행해 불필요한 덮어쓰기를 줄이고 성능을 향상합니다. use_replace_on_for_insert_overwrite를 SQL 웨어하우스에서 false로 설정하면 dbt는 새 데이터를 삽입하기 전에 전체 테이블을 truncate(비움)합니다. 이는 모델이 실행될 때마다 테이블의 모든 행을 교체하므로 대용량 데이터셋에서 실행 시간과 비용이 늘어날 수 있습니다. partition_byliquid_clustered_by를 지정하지 않으면 insert_overwrite 전략은 테이블의 모든 내용을 원자적으로 교체해 기존 데이터를 새 레코드로만 덮어씁니다. 다만 테이블의 컬럼 스키마는 동일하게 유지됩니다. 테이블 내용이 덮여 쓰이는 동안 가동 중지 시간을 최소화하므로 일부 제한된 상황에서 바람직할 수 있어요. 이 작업은 다른 데이터베이스의 truncateinsert를 실행하는 것과 비교됩니다. Delta 형식 테이블의 원자적 교체에는 대신 table materialization(create or replace 실행)을 사용하세요.

원본 코드 (databricks_incremental.sql):

{{ config(
  materialized = 'incremental',
  partition_by = ['date_day'],
  file_format = 'parquet'
) }}
/*
이 쿼리가 반환하는 모든 파티션은
이 모델이 실행될 때 덮어써집니다
*/
with new_events as (
  select * from {{ ref('events') }}
  {% if is_incremental() %}
  where date_day >= date_add(current_date, -1)
  {% endif %}
)
select date_day, count(*) as users from new_events group by 1

컴파일된 코드 (databricks_incremental.sql):

create temporary view databricks_incremental__dbt_tmp as
with new_events as (
  select * from analytics.events
  where date_day >= date_add(current_date, -1)
)
select date_day, count(*) as users from events group by 1;
insert overwrite table analytics.databricks_incremental partition (date_day)
select `date_day`, `users` from databricks_incremental__dbt_tmp

merge 전략

merge 점진적 전략은 다음을 요구합니다.

  • file_format: delta or hudi
  • delta 파일 형식은 Databricks Runtime 5.1 이상
  • hudi 파일 형식은 Apache Spark

Databricks 어댑터는 Snowflake와 BigQuery의 기본 merge 동작과 유사한 atomic merge 문을 실행합니다. unique_key가 지정되면(권장) dbt는 키 컬럼에서 일치하는 새 레코드의 값으로 기존 레코드를 업데이트합니다. unique_key가 지정되지 않으면 dbt는 매칭 기준을 생략하고 단순히 모든 새 레코드를 삽입합니다(append 전략과 유사). 어떤 것도 지정하지 않았을 때의 기본 전략이므로 merge를 점진적 전략으로 지정하는 것은 선택 사항입니다.

원본 코드 (merge_incremental.sql):

{{ config(
  materialized = 'incremental',
  file_format = 'delta',
  # or 'hudi'
  unique_key = 'user_id',
  incremental_strategy = 'merge'
) }}
with new_events as (
  select * from {{ ref('events') }}
  {% if is_incremental() %}
  where date_day >= date_add(current_date, -1)
  {% endif %}
)
select user_id, max(date_day) as last_seen from events group by 1

컴파일된 코드 (target/run/merge_incremental.sql):

create temporary view merge_incremental__dbt_tmp as
with new_events as (
  select * from analytics.events
  where date_day >= date_add(current_date, -1)
)
select user_id, max(date_day) as last_seen from events group by 1;
merge into analytics.merge_incremental as DBT_INTERNAL_DEST
using merge_incremental__dbt_tmp as DBT_INTERNAL_SOURCE
on DBT_INTERNAL_SOURCE.user_id = DBT_INTERNAL_DEST.user_id
when matched then update set *
when not matched then insert *

1.9부터 merge 동작은 다음 추가 구성 옵션으로 수정할 수 있습니다.

  • target_alias, source_alias: target과 source의 별칭으로 merge 조건을 더 자연스럽게 설명할 수 있게 해줍니다. 각각 DBT_INTERNAL_DESTDBT_INTERNAL_SOURCE가 기본값입니다.
  • skip_matched_step: true로 설정하면 merge 문의 'matched' 절이 포함되지 않습니다.
  • skip_not_matched_step: true로 설정하면 'not matched' 절이 포함되지 않습니다.
  • matched_condition: WHEN MATCHED 절에 적용할 조건. target_aliassource_alias를 사용해 DBT_INTERNAL_DEST.col1 = hash(DBT_INTERNAL_SOURCE.col2, DBT_INTERNAL_SOURCE.col3) 같은 조건식을 작성해야 합니다. 이 조건은 일치하는 행 집합을 더 제한합니다.
  • not_matched_condition: WHEN NOT MATCHED [BY TARGET] 절에 적용할 조건. 이 조건은 병합된 테이블에 삽입될 source와 일치하지 않는 대상 테이블의 행 집합을 더 제한합니다.
  • not_matched_by_source_condition: 추가 필터링 WHEN NOT MATCHED BY SOURCE 절에 적용할 조건. not_matched_by_source_action과 함께만 사용됩니다.
  • not_matched_by_source_action: 조건이 충족될 때 적용할 조치. 표현식으로 구성합니다. 예: not_matched_by_source_action: "update set t.attr1 = 'deleted', t.tech_change_ts = current_timestamp()".
  • merge_with_schema_evolution: true로 설정하면 merge 문에 WITH SCHEMA EVOLUTION 절이 포함됩니다.

각 merge 절의 의미에 대한 자세한 내용은 Databricks 문서를 참고하세요.

아래는 이 새 옵션들의 사용을 보여주는 예시입니다.

원본 코드 (merge_incremental_options.sql):

{{ config(
  materialized = 'incremental',
  unique_key = 'id',
  incremental_strategy = 'merge',
  target_alias = 't',
  source_alias = 's',
  matched_condition = 't.tech_change_ts < s.tech_change_ts',
  not_matched_condition = 's.attr1 IS NOT NULL',
  not_matched_by_source_condition = 't.tech_change_ts < current_timestamp()',
  not_matched_by_source_action = 'delete',
  merge_with_schema_evolution = true
) }}
select id, attr1, attr2, tech_change_ts
from {{ ref('source_table') }} as s

컴파일된 코드 (target/run/merge_incremental_options.sql):

create temporary view merge_incremental__dbt_tmp as
select id, attr1, attr2, tech_change_ts from upstream.source_table;
merge with schema evolution into target_table as t
using (select id, attr1, attr2, tech_change_ts from source_table as s)
on t.id <=> s.id
when matched and t.tech_change_ts < s.tech_change_ts then update set
  id = s.id, attr1 = s.attr1, attr2 = s.attr2, tech_change_ts = s.tech_change_ts
when not matched and s.attr1 IS NOT NULL then insert (id, attr1, attr2, tech_change_ts)
  values (s.id, s.attr1, s.attr2, s.tech_change_ts)
when not matched by source and t.tech_change_ts < current_timestamp() then delete

replace_where 전략

replace_where 점진적 전략은 다음을 요구합니다.

  • file_format: delta
  • Databricks Runtime 12.0 이상

dbt는 문자열이나 배열로 지정된 하나 이상의 incremental_predicates와 일치하는 데이터를 선택적으로 덮어쓰는 atomic replace where 문을 실행합니다. 조건과 일치하는 행만 삽입됩니다. incremental_predicates가 지정되지 않으면 dbt는 append처럼 원자적 삽입을 수행합니다.

주의: replace_where는 컬럼 이름이 아닌 제공된 순서대로 데이터를 삽입합니다. 컬럼을 재정렬하고 데이터가 기존 스키마와 호환되면 의도치 않은 컬럼에 값이 조용히 삽입될 수 있어요. 들어오는 데이터가 기존 스키마와 호환되지 않으면 대신 오류가 발생합니다.

원본 코드 (replace_where_incremental.sql):

{{ config(
  materialized = 'incremental',
  file_format = 'delta',
  incremental_strategy = 'replace_where'
  incremental_predicates = 'user_id >= 10000'
  # id가 10000보다 작은 사용자는 절대 교체하지 않음
) }}
with new_events as (
  select * from {{ ref('events') }}
  {% if is_incremental() %}
  where date_day >= date_add(current_date, -1)
  {% endif %}
)
select user_id, max(date_day) as last_seen from events group by 1

컴파일된 코드 (target/run/replace_where_incremental.sql):

create temporary view replace_where__dbt_tmp as
with new_events as (
  select * from analytics.events
  where date_day >= date_add(current_date, -1)
)
select user_id, max(date_day) as last_seen from events group by 1;
insert into analytics.replace_where_incremental
replace where user_id >= 10000 table `replace_where__dbt_tmp`

delete+insert 전략

버전 1.11 이상에서 사용 가능

delete+insert 점진적 전략은 다음을 요구합니다.

  • file_format: delta
  • 필수 unique_key 구성
  • Databricks Runtime 12.2 LTS 이상

delete+insert 전략은 특정 컬럼을 업데이트하는 복잡성 없이 일치하는 레코드를 교체하려는 경우 merge 전략의 더 단순한 대안입니다. 이 전략은 두 단계로 작동합니다.

  1. 삭제(Delete): unique_key가 새 데이터의 행과 일치하는 대상 테이블의 모든 행을 제거합니다.
  2. 삽입(Insert): 스테이징 데이터의 모든 새 행을 삽입합니다.

이 전략은 특히 다음 경우에 유용합니다.

  • 특정 컬럼을 업데이트하기보다 전체 레코드를 교체하려는 경우
  • 비즈니스 로직이 깔끔한 "제거 후 교체" 방식을 요구하는 경우
  • 전체 레코드 교체에 대해 merge보다 더 단순한 점진적 전략이 필요한 경우

Databricks Runtime 17.1 이상을 사용하면 dbt는 효율적인 INSERT INTO ... REPLACE ON 구문을 사용해 이 작업을 원자적으로 수행합니다. 이전 런타임 버전에서는 dbt가 별도의 DELETEINSERT 문을 실행합니다. 선택적으로 incremental_predicates를 사용해 처리되는 레코드를 추가로 필터링해, 삭제되고 삽입되는 행을 더 제어할 수 있어요.

원본 코드 (delete_insert_incremental.sql):

{{ config(
  materialized = 'incremental',
  file_format = 'delta',
  incremental_strategy = 'delete+insert',
  unique_key = 'user_id',
  incremental_predicates = 'user_id >= 10000'
  # id가 10000보다 작은 사용자는 절대 삭제/삽입하지 않음
) }}
with new_events as (
  select * from {{ ref('events') }}
  {% if is_incremental() %}
  where date_day >= date_add(current_date, -1)
  {% endif %}
)
select user_id, max(date_day) as last_seen from new_events group by 1

컴파일된 코드 — DBR 17.1+ (target/run/delete_insert_incremental.sql):

create temporary view delete_insert_incremental__dbt_tmp as
with new_events as (
  select * from analytics.events
  where date_day >= date_add(current_date, -1)
)
select user_id, max(date_day) as last_seen from new_events group by 1;
insert into table analytics.delete_insert_incremental as target
replace on (target.user_id <=> temp.user_id)
(select `user_id`, `last_seen` from delete_insert_incremental__dbt_tmp where user_id >= 10000) as temp

컴파일된 코드 — DBR < 17.1 (target/run/delete_insert_incremental.sql):

create temporary view delete_insert_incremental__dbt_tmp as
with new_events as (
  select * from analytics.events
  where date_day >= date_add(current_date, -1)
)
select user_id, max(date_day) as last_seen from new_events group by 1;
-- 1단계: 일치하는 행 삭제
delete from analytics.delete_insert_incremental
where analytics.delete_insert_incremental.user_id IN (SELECT user_id FROM delete_insert_incremental__dbt_tmp)
and user_id >= 10000;
-- 2단계: 새 행 삽입
insert into analytics.delete_insert_incremental by name
select `user_id`, `last_seen` from delete_insert_incremental__dbt_tmp where user_id >= 10000

microbatch 전략

버전 1.9 이상에서 사용 가능

Databricks 어댑터는 replace_where를 사용해 microbatch 전략을 구현합니다. 위의 replace_where 요구사항과 주의 사항을 참고하세요. 이 전략에 대한 자세한 내용은 microbatch 참조 페이지를 참고하세요.

다음 예시에서 업스트림 테이블 events는 스키마 파일에 ts라는 event_time 컬럼이 주석으로 추가되어 있습니다.

원본 코드 (microbatch_incremental.sql):

{{ config(
  materialized = 'incremental',
  file_format = 'delta',
  incremental_strategy = 'microbatch'
  event_time = 'date'
  # 이 microbatch 테이블의 grain으로 'date' 사용
) }}
with new_events as (
  select * from {{ ref('events') }} )
select user_id, date, count(*) as visits from events group by 1, 2

컴파일된 코드 (target/run/replace_where_incremental.sql):

create temporary view replace_where__dbt_tmp as
with new_events as (
  select * from (
    select * from analytics.events
    where ts >= '2024-10-01' and ts < '2024-10-02'
  )
)
select user_id, date, count(*) as visits from events group by 1, 2;
insert into analytics.replace_where_incremental
replace where CAST(date as TIMESTAMP) >= '2024-10-01' and CAST(date as TIMESTAMP) < '2024-10-02'
table `replace_where__dbt_tmp`

Python 모델 구성

Databricks 어댑터는 Python 모델을 지원합니다. Databricks는 이 모델들의 처리 프레임워크로 PySpark를 사용합니다.

제출 방법(Submission methods): Databricks는 PySpark 코드를 제출하는 몇 가지 서로 다른 메커니즘을 지원하며, 각각 상대적인 장점이 있어요. 일부는 반복적 개발을 지원하는 데 더 좋고, 일부는 더 저렴한 프로덕션 배포를 지원하는 데 더 좋습니다. 옵션은 다음과 같아요.

  • all_purpose_cluster(기본값): dbt는 연결 프로필이나 이 특정 모델에 cluster로 구성된 클러스터 ID를 사용해 Python 모델을 실행합니다. 이 클러스터는 더 비싸지만 훨씬 응답성이 높습니다. 개발에서 더 빠른 반복을 위해 대화형 all-purpose 클러스터를 권장합니다.
  • create_notebook: True: dbt는 모델의 컴파일된 PySpark 코드를 /Shared/dbt_python_model/{schema} 네임스페이스의 노트북에 업로드하고({schema}는 모델에 구성된 스키마), 해당 노트북을 실행해 all-purpose 클러스터로 실행합니다. 이 방식의 장점은 모델을 실행한 직후 디버깅이나 미세 조정을 위해 Databricks UI에서 노트북을 쉽게 열 수 있다는 점입니다. 다시 실행하기 전에 dbt .py 모델 코드에 변경 사항을 복사하는 것을 기억하세요.
  • create_notebook: False(기본값): dbt는 약간 더 빠른 Command API를 사용합니다.
  • job_cluster: dbt는 모델의 컴파일된 PySpark 코드를 /Shared/dbt_python_model/{schema} 네임스페이스의 노트북에 업로드하고({schema}는 모델에 구성된 스키마), 해당 노트북을 실행해 수명이 짧은 jobs 클러스터로 실행합니다. 각 Python 모델에 대해 Databricks는 클러스터를 띄우고, 모델의 PySpark 변환을 실행한 뒤, 클러스터를 내립니다. 따라서 job 클러스터는 모델 실행 전후에 더 오래 걸리지만 비용도 더 저렴해서, 프로덕션의 장시간 실행 Python 모델에 권장합니다. job_cluster 제출 방법을 사용하려면 모델이 new_cluster의 키-값 속성을 정의하는 job_cluster_config로 구성되어 있어야 합니다(JobRunsSubmit API에 정의됨).

각 모델의 submission_method는 구성을 제공하는 모든 표준 방식으로 구성할 수 있습니다.

def model(dbt, session):
    dbt.config(
        submission_method = "all_purpose_cluster",
        create_notebook = True,
        cluster_id = "abcd-1234-wxyz"
    )
    ...
models:
  - name: my_python_model
    config:
      submission_method: job_cluster
      job_cluster_config:
        spark_version: ...
        node_type_id: ...
# dbt_project.yml
models:
  project_name:
    subfolder:
      # 이 하위 폴더에 정의된 모든 .py 모델 기본값 설정
      +submission_method: all_purpose_cluster
      +create_notebook: False
      +cluster_id: abcd-1234-wxyz

구성되지 않으면 dbt-spark는 내장 기본값을 사용합니다: 노트북을 만들지 않는 all-purpose 클러스터(연결 프로필의 cluster 기반). dbt-databricks 어댑터는 http_path에 구성된 클러스터를 기본값으로 합니다. Databricks 프로젝트에서 Python 모델용 클러스터를 명시적으로 구성하는 것을 권장합니다.

패키지 설치: all-purpose 클러스터를 사용할 때는 Python 모델 실행에 사용할 패키지를 설치하는 것을 권장합니다.

관련 문서:

  • PySpark DataFrame 구문
  • Databricks: Introduction to DataFrames - Python

모델별 컴퓨팅 선택하기

버전 1.7.2부터 모델별로 사용할 컴퓨팅 리소스를 지정할 수 있습니다. SQL 모델의 경우 SQL Warehouse(serverless 또는 provisioned)나 all purpose cluster를 선택할 수 있습니다. 이 기능이 Python 모델과 어떻게 상호작용하는지에 대한 자세한 내용은 Python 모델용 컴퓨팅 지정을 참고하세요.

참고: 이것은 선택적 설정입니다. 아래처럼 구성하지 않으면 프로필의 output 섹션 최상위 http_path가 지정하는 컴퓨팅이 기본값이 됩니다. 이것은 또한 특정 모델과 연결되지 않은 작업(예: 스키마의 모든 테이블에 대한 메타데이터 수집)에도 사용되는 컴퓨팅입니다.

이 기능을 활용하려면 프로필에 compute 블록을 추가해야 합니다.

profiles.yml:

profile-name:
  target: target-name # this is the default target
  outputs:
    target-name:
      type: databricks
      catalog: optional catalog name if you are using Unity Catalog
      schema: schema name
      # Required
      host: yourorg.databrickshost.com
      # Required
      ### 이 경로는 기본 컴퓨팅으로 사용됨
      http_path: /sql/your/http/path
      # Required
      ### 새 compute 섹션
      compute:
        ### 대체 컴퓨팅을 참조하는 데 사용할 이름
        Compute1:
          http_path: '/sql/your/http/path'
          # 각 대체 컴퓨팅에 필수
        ### 세 번째 이름 붙은 컴퓨팅, 원하는 이름을 사용
        Compute2:
          http_path: '/some/other/path'
          # 각 대체 컴퓨팅에 필수
        ...
    target-name:
      # 추가 타겟
      ...
      ### 각 타겟에 대해 동일한 compute를 정의해야 하지만,
      ### 다른 경로를 지정할 수 있음
      compute:
        ### 대체 컴퓨팅을 참조하는 데 사용할 이름
        Compute1:
          http_path: '/sql/your/http/path'
          # 각 대체 컴퓨팅에 필수
        ### 세 번째 이름 붙은 컴퓨팅, 원하는 이름을 사용
        Compute2:
          http_path: '/some/other/path'
          # 각 대체 컴퓨팅에 필수
        ...

새 compute 섹션은 사용자가 선택한 이름과 http_path 속성을 가진 객체의 맵입니다. 각 compute는 모델 정의/구성에서 해당 모델/모델 그룹에 사용하려는 컴퓨팅을 나타내는 이름으로 키가 지정됩니다. Databricks UI 내부의 컴퓨팅 리소스 이름처럼 사용 중인 컴퓨팅 리소스로 쉽게 인식되는 이름을 선택하는 것을 권장합니다.

참고: output 전체에서 compute에 동일한 이름 집합을 사용해야 하지만, 서로 다른 http_path를 제공할 수 있어 배포 시나리오에 따라 다른 컴퓨팅을 사용할 수 있습니다.

dbt 내부에서 구성하려면 원하는 환경의 extended attributes 기능을 사용하세요.

compute:
  Compute1:
    http_path: /SOME/OTHER/PATH
  Compute2:
    http_path: /SOME/OTHER/PATH

모델의 컴퓨팅 지정하기

다른 많은 구성 옵션과 마찬가지로 databricks_compute로 모델의 컴퓨팅을 여러 방식으로 지정할 수 있습니다.

dbt_project.yml에서 선택한 컴퓨팅을 주어진 디렉터리의 모든 모델에 대해 지정할 수 있어요.

dbt_project.yml:

...
models:
  +databricks_compute: "Compute1"
  # 프로젝트의 모든 모델에 `Compute1` 웨어하우스/클러스터 사용...
  my_project:
    clickstream:
      +databricks_compute: "Compute2"
  # ...단 `clickstream` 폴더의 모델은 제외, `Compute2` 사용
snapshots:
  +databricks_compute: "Compute1"
  # 모든 Snapshot 모델은 `Compute1`을 사용하도록 구성됨

개별 모델의 경우 스키마 파일의 모델 구성에서 컴퓨팅을 지정할 수 있어요.

schema.yml:

models:
  - name: table_model
    config:
      databricks_compute: Compute1
    columns:
      - name: id
        data_type: int

또는 웨어하우스를 모델의 SQL 파일 구성에서 지정할 수 있습니다.

model.sql:

{{ config(
  materialized = 'table',
  databricks_compute = 'Compute1'
) }}
select * from {{ ref('seed') }}

지정한 컴퓨팅이 사용되고 있는지 확인하려면 dbt.log에서 다음과 같은 줄을 찾으세요.

  • Databricks adapter ... using default compute resource.
  • 또는 Databricks adapter ... using compute resource <name of compute>.

Python 모델용 컴퓨팅 지정하기

Python 모델을 구체화하려면 SQL과 python 둘 다 실행해야 해요. 구체적으로 Python 모델이 점진적이면 현재 실행 패턴은 python을 실행해 스테이징 테이블을 만든 다음 SQL을 사용해 대상 테이블에 병합하는 것을 포함합니다. Python 코드는 all purpose cluster(또는 serverless cluster, Python 제출 방법 참고)에서 실행해야 하고, SQL 코드는 all purpose cluster나 SQL Warehouse에서 실행할 수 있어요.

Python 모델에 databricks_compute를 지정하면 현재는 모델별 SQL 실행 시 사용할 컴퓨팅만 지정하는 것입니다. python 자체를 실행하는 데 다른 컴퓨팅을 사용하려면 모델 구성에서 대체 컴퓨팅을 지정해야 합니다.

예를 들어:

def model(dbt, session):
    dbt.config(
        http_path = "sql/protocolv1/..."
    )

기본 컴퓨팅이 SQL Warehouse라면 이런 식으로 all purpose cluster http_path를 지정해야 합니다.

모델 설명 영구화

관계 수준 문서 영구화가 지원됩니다. 문서 영구화 구성에 대한 자세한 내용은 문서를 참고하세요. persist_docs 옵션이 적절히 구성되면 describe [table] extended 또는 show table extended in [database] like '*'Comment 필드에서 모델 설명을 볼 수 있어요.

쿼리 태그

버전 1.11 이상에서 사용 가능

쿼리 태그는 SQL 쿼리에 커스텀 키-값 메타데이터를 붙일 수 있는 Databricks 기능입니다. 이 메타데이터는 시스템 테이블과 쿼리 기록에 나타나므로 쿼리 비용 추적, 디버깅, 감사에 유용합니다.

기능 가용성: 쿼리 태그는 아직 모든 Databricks 워크스페이스에서 사용 가능하지 않을 수 있어요. 기능 가용성에 대한 최신 정보는 Databricks 문서를 확인하세요.

dbt-databricks는 연결 수준(프로필)과 모델 수준(모델 구성) 모두에서 쿼리 태그 설정을 지원합니다. dbt 실행 시 모델 이름과 dbt 버전 같은 dbt 메타데이터를 담은 기본 태그를 자동으로 포함해요.

기본 쿼리 태그: dbt-databricks는 모든 쿼리에 다음 태그를 자동으로 추가합니다.

태그 키 설명
@@dbt_model_name 실행 중인 모델의 이름
@@dbt_core_version 사용 중인 dbt 버전
@@dbt_databricks_version 사용 중인 dbt-databricks 버전
@@dbt_materialized 구체화 유형(table, view, incremental 등)

이 예약 키는 사용자 정의 태그로 덮어쓸 수 없습니다.

쿼리 태그 구성하기: 프로필의 연결 수준이나 모델 구성의 모델 수준에서 쿼리 태그를 설정할 수 있어요. 모델 수준 태그가 연결 수준 태그보다 우선합니다.

연결 수준 쿼리 태그 — 연결의 모든 쿼리에 쿼리 태그를 설정하려면 ~/.dbt/profiles.yml 파일에 JSON 문자열로 query_tags 파라미터를 추가하세요.

your_profile_name:
  target: dev
  outputs:
    dev:
      type: databricks
      catalog: my_catalog
      schema: my_schema
      host: yourorg.databrickshost.com
      http_path: /sql/your/http/path
      token: dapiXXXXXXXXXXXXXXXXXXXXXXX
      query_tags: '{"team": "analytics", "project": "customer_360"}'

모델 수준 쿼리 태그 — 특정 모델에 쿼리 태그를 설정하려면 query_tags 구성을 사용하세요.

models/my_model.sql:

{{ config(
  query_tags = {
    'cost_center': 'marketing',
    'priority': 'high'
  }
) }}
select * from {{ ref('upstream_model') }}

모델 그룹에 대해 dbt_project.yml에서도 쿼리 태그를 구성할 수 있어요.

models:
  my_project:
    marketing:
      +query_tags: { 'department': 'marketing' }
    finance:
      +query_tags: { 'department': 'finance' }

태그 우선순위와 병합: 여러 수준에서 쿼리 태그가 정의되면 다음 우선순위(높은 것부터 낮은 것)로 병합됩니다.

  1. 모델 수준 태그(config() 또는 schema.yml에서)
  2. 연결 수준 태그(profiles.yml에서)
  3. 기본 dbt 태그(자동 추가)

같은 키가 여러 수준에 나타나면 더 높은 우선순위의 값이 우선해요.

연결 수준 태그를 쓰는 이유: dbt가 구성 병합 방식 때문에 config() 또는 schema.yml의 모델 수준에서 query_tags를 지정하면 dbt_project.yml에 정의한 query_tags를 병합하는 대신 교체합니다. 이는 사전 구성에 대한 표준 dbt 동작입니다. 이 제한을 우회하기 위해 dbt-databricks는 연결 프로필(profiles.yml)에서 query_tags를 허용합니다. 연결 수준 태그는 항상 모델 수준 태그와 병합되므로, 공통 태그를 프로필에 한 번 정의하고 모델 수준에서 특정 키만 선택적으로 추가하거나 덮어쓸 수 있어요.

권장 패턴:

  • 프로필의 query_tags에 공유 태그(team, project, environment)를 정의하세요.
  • 모델별 태그를 추가해야 할 때는 모델 수준 query_tags를 사용하세요.

제한 사항:

  • 최대 20개 태그: 쿼리 태그 총 수(기본 태그 포함)는 20을 초과할 수 없습니다.
  • 값 길이: 태그 값은 최대 128자여야 합니다. 이 한도를 초과하는 기본 태그 값은 자동으로 잘립니다.
  • 특수 문자: 태그 값의 백슬래시(\), 쉼표(,), 콜론(:) 문자는 자동으로 이스케이프됩니다. 이스케이프 발생 시 경고가 기록됩니다.
  • 예약 키: @@dbt_model_name, @@dbt_core_version, @@dbt_databricks_version, @@dbt_materialized 키는 예약되어 있어 사용자 정의 태그에 사용할 수 없습니다.

쿼리 태그 보기: 쿼리 태그는 Databricks 시스템 테이블과 쿼리 기록에 나타납니다. 쿼리 태그를 조회하고 분석하는 방법은 Databricks 쿼리 태그 문서를 참고하세요.

기본 파일 형식 구성

스냅샷merge 점진적 전략 같은 고급 점진적 전략 기능에 접근하려면 모델을 테이블로 구체화할 때 Delta 또는 Hudi 파일 형식을 기본 파일 형식으로 사용하고 싶을 거예요. 프로젝트 파일에서 최상위 구성을 설정하면 매우 편리합니다.

dbt_project.yml:

models:
  +file_format: delta
  # or hudi
seeds:
  +file_format: delta
  # or hudi
snapshots:
  +file_format: delta
  # or hudi

구체화된 뷰와 스트리밍 테이블

구체화된 뷰스트리밍 테이블Delta Live Tables로 구동되는 점진적 테이블의 대안입니다. 자세한 내용과 사용 사례는 Delta Live Tables란 무엇인가요?를 참고하세요.

이 구체화 전략을 채택하려면 Unity Catalog와 serverless SQL Warehouses가 활성화된 워크스페이스가 필요합니다.

materialized_view.sql:

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

또는 streaming_table.sql:

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

이 materialization의 대부분의 사용 가능한 속성에 대해 on_configuration_change를 지원합니다. 다음 표는 구성 지원을 요약합니다. 각 config에 대한 자세한 내용은 구성 세부 정보를 참고하세요.

Databricks 개념 구성 이름 MV/ST 지원 버전
PARTITIONED BY partition_by MV/ST All
CLUSTER BY liquid_clustered_by MV/ST v1.11+
COMMENT description MV/ST All
TBLPROPERTIES tblproperties MV/ST All
TAGS databricks_tags MV/ST v1.11+
SCHEDULE CRON schedule: { 'cron': '<cron schedule>', 'time_zone_value': '<time zone value>' } MV/ST All
SCHEDULE EVERY schedule: { 'every': '<n> <unit>' } MV/ST v1.12+
TRIGGER ON UPDATE schedule: { 'on_update': true, 'at_most_every': '<n> <unit>' } MV/ST v1.12+
WITH ROW FILTER row_filter MV/ST v1.12+
query 모델 SQL로 정의됨 MV 전용에서 on_configuration_change All

mv_example.sql:

{{ config(
  materialized = 'materialized_view',
  partition_by = 'id',
  schedule = {
    'cron': '0 0 * * * ? *',
    'time_zone_value': 'Etc/UTC'
  },
  tblproperties = { 'key': 'value' },
) }}
select * from {{ ref('my_seed') }}

구성 세부 정보

  • partition_by: 뷰와 테이블과 동일하게 작동하며, 파티셔닝할 단일 컬럼 또는 컬럼 배열일 수 있어요.
  • liquid_clustered_by (버전 1.11 이상): 구체화된 뷰와 스트리밍 테이블에 liquid clustering을 활성화합니다. Liquid clustering은 유사한 데이터를 같은 파일 내에 공동 배치해 쿼리 성능을 최적화하며, 클러스터링된 컬럼에 선택적 필터가 있는 쿼리에 특히 유용합니다. 참고: 같은 materialization에서 partition_byliquid_clustered_by를 둘 다 사용할 수 없습니다. Databricks는 이 기능들의 결합을 허용하지 않습니다.
  • databricks_tags (버전 1.11 이상): 데이터 거버넌스와 조직화를 위해 구체화된 뷰와 스트리밍 테이블에 Unity Catalog 태그를 적용할 수 있게 해줍니다. 태그는 데이터 분류, 접근 제어 정책, 메타데이터 관리에 사용할 수 있는 키-값 쌍이에요.
{{ config(
  materialized = 'streaming_table',
  databricks_tags = {
    'pii': 'contains_email',
    'team': 'analytics'
  }
) }}

dbt-databricks v1.12+는 키 전용 태그를 지원합니다. 키는 있지만 값이 없는 태그를 설정하려면 태그 값을 빈 문자열 '' 또는 None으로 설정하세요.

{{ config(
  materialized = 'streaming_table',
  databricks_tags = {
    'sensitive': '',
    'reviewed': None}
) }}

이는 테이블 수준과 컬럼 수준 databricks_tags 모두에 적용됩니다. 숫자나 boolean 같은 비문자열 값은 문자열로 변환됩니다. 태그는 materialization이 생성된 후 ALTER 문으로 적용됩니다. 적용된 후에는 dbt-databricks 구성 변경으로 태그를 제거할 수 없어요. 태그를 제거하려면 Databricks를 직접 사용하거나 post-hook을 사용해야 합니다.

v1.12의 동작 변경: dbt-databricks v1.12.0부터 databricks_tags 구성은 낮은 수준의 구성이 높은 수준을 완전히 대체하는 대신 구성 계층(예: 프로젝트 수준과 모델 수준) 전반에 걸쳐 가산적으로 병합됩니다. 같은 태그 키가 여러 수준에 정의되면 낮은 수준의 값이 우선합니다. 높은 수준에서만 정의된 태그 키는 유지됩니다. 이 동작은 테이블, 컬럼, 구체화된 뷰, 스트리밍 테이블을 포함해 databricks_tags를 구성할 수 있는 모든 곳에 적용됩니다.

예를 들어 다음 프로젝트 수준과 모델 수준 구성으로:

dbt_project.yml:

models:
  my_project:
    +databricks_tags:
      a: "b"
      c: "project_value"

models/my_model.sql:

{{ config(
  databricks_tags = {
    'c': 'model_value',
    'k': 'v'
  }
) }}

결과 태그는 다음과 같습니다.

  • a: b — 프로젝트 수준에서 유지됨

  • c: model_value — 모델 수준 값이 프로젝트 수준 c를 덮어씀

  • k: v — 모델 수준에서 추가됨

  • description: 뷰와 테이블과 마찬가지로 구성에 description을 추가하면 materialization에 테이블 수준 주석이 추가됩니다.

  • tblproperties: 뷰와 테이블과 동일하게 작동하지만 중요한 예외가 있습니다: 어댑터는 Databricks가 구체화된 뷰나 스트리밍 테이블을 만들 때 설정하는 키 목록을 유지하며, 이 키들은 구성 변경을 결정하는 목적에서는 무시됩니다.

  • schedule: 세 가지 상호 배타적 모드 중 하나로 모델의 새로고침 일정을 설정하세요.

모드 구성 형식 버전
cron schedule: { 'cron': '...', 'time_zone_value': '...' } Cron 문자열(Databricks 형식). time_zone_value는 선택. All
every schedule: { 'every': ' ' } <n> <unit> — unit은 HOURS, DAYS, WEEKS — 예: '2 HOURS' v1.12+
on_update schedule: { 'on_update': true, 'at_most_every': ' ' } true로 설정하면 업스트림 데이터가 변경될 때 새로고침. at_most_every는 선택 사항으로 새로고침을 rate-limit(최소 60초). 예: '15 MINUTES' v1.12+

모드별 새로고침 동작:

  • cron: dbt가 매 실행마다 수동 새로고침을 요청합니다.

  • everyon_update: Databricks가 새로고침을 자동 관리합니다. dbt는 no-op 재실행 시 수동 새로고침을 트리거하지 않습니다.

  • Databricks에 일정이 있지만 dbt 프로젝트가 지정하지 않으면(on_configuration_changeapply일 때) 다음 실행에서 일정이 수동으로 재설정됩니다.

  • query: 구체화된 뷰에서 컴파일된 쿼리가 데이터베이스의 것과 다르면 dbt가 구성된 on_configuration_change 작업을 수행합니다. 쿼리 변경은 현재 스트리밍 테이블에서는 감지되지 않습니다. 자세한 내용은 on_configuration_change를 참고하세요.

  • row_filter (버전 1.12 이상): 모델에 Unity Catalog 행 필터를 적용합니다. table, incremental, materialized_view, streaming_table 구체화에서 지원됩니다. 전체 구성 참조와 예시는 행 필터 설정을 참고하세요.

  • on_configuration_change:

Materialization 드롭 후 재생성 필요? 참고
구체화된 뷰 예, 일정 업데이트를 제외한 모든 변경에 대해 Databricks SQL API 제한
스트리밍 테이블 partition_by가 변경될 때만 다른 모든 지원 변경은 CREATE OR REFRESH + 일정 변경용 ALTER 사용

스트리밍 테이블 쿼리 변경에 대한 참고: 현재 어댑터가 스트리밍 테이블 쿼리가 변경되었는지 감지할 방법이 없습니다. on_configuration_change 동작과 관계없이 dbt는 CREATE OR REFRESH를 사용하며, 이는 업데이트된 쿼리를 향후 행에만 적용합니다 — 이전에 처리된 행은 재처리되지 않습니다. 업데이트된 쿼리로 사용 가능한 원본 데이터를 재처리하려면 --full-refresh로 실행하세요. (dbt v1.12 이상 적용)

메트릭 뷰

materialized='metric_view'를 설정해 dbt로 Unity Catalog 메트릭 뷰를 관리합니다. SQL 대신 모델의 본문은 메트릭 뷰의 YAML 정의입니다: version, source, dimensions, measures, 선택적 filter. dbt는 CREATE OR REPLACE VIEW ... WITH METRICS LANGUAGE YAML로 메트릭 뷰를 만듭니다.

order_metrics.sql:

{{ config(
  materialized = 'metric_view'
) }}
version: 1.1
source: "{{ ref('source_orders') }}"
filter: status = 'completed'
dimensions:
  - name: order_date
    expr: order_date
  - name: status
    expr: status
    synonyms: [state, order_state]
measures:
  - name: total_orders
    expr: count(1)
  - name: total_revenue
    expr: sum(revenue)
    synonyms: [revenue, sales]

source에서 원본 관계를 ref()로 참조해 dbt가 의존성을 해결하게 하세요. 결과 메트릭 뷰는 MEASURE() 함수로 조회합니다. dbt는 YAML 본문을 변경 없이 Databricks로 전달하므로, 메트릭 뷰는 위에 표시된 키뿐 아니라 전체 Unity Catalog 메트릭 뷰 YAML 명세를 지원합니다. Databricks가 서버 측에서 허용하는 모든 필드가 dbt를 통해 작동합니다 — dimensions와 measures의 synonymsdisplay_name, measures의 formatwindow 포함.

메트릭 뷰에 databricks_tagsgrants를 설정할 수도 있어요. tblproperties는 뷰가 제자리에서 업데이트(view_update_via_alter)되거나 교체될 때만 적용되며, 최초 생성 시에는 적용되지 않습니다.

메트릭 뷰 업데이트하기: 기본적으로 dbt는 매 실행마다 CREATE OR REPLACE VIEW로 메트릭 뷰를 다시 만듭니다. view_update_via_altertrue로 설정하면 dbt가 뷰를 교체하는 대신 제자리에서 점진적 변경을 적용합니다.

  • YAML 정의 변경은 ALTER VIEW ... AS로 적용됩니다.
  • databricks_tags 또는 tblproperties 변경은 ALTER VIEW ... SET로 적용됩니다.
  • 정의도 태그나 속성도 변경되지 않으면 dbt는 업데이트를 건너뜁니다.

테이블 속성 설정

테이블이나 뷰의 구성으로 tblproperties를 사용해 테이블 속성을 설정할 수 있어요.

with_table_properties.sql:

{{ config(
  tblproperties = {
    'delta.autoOptimize.optimizeWrite': 'true',
    'delta.autoOptimize.autoCompact': 'true'
  }
) }}

주의: 이 속성은 dbt에서 검증 없이 Databricks로 직접 전송됩니다. 점진적 materialization의 tblproperties를 변경하면 전체 새로고침을 해야 합니다. 한 가지 사용 사례는 Universal Format을 사용해 delta 테이블을 iceberg 리더와 호환되게 만드는 것입니다.

{{ config(
  tblproperties = {
    'delta.enableIcebergCompatV2' = 'true'
    'delta.universalFormat.enabledFormats' = 'iceberg'
  }
) }}

tblproperties는 Python 모델에도 지정할 수 있지만, PySpark 제한 때문에 테이블 생성 후 ALTER 문으로 적용됩니다.

더 알아보기 (Learn more)

Databricks 구성은 dbt-databricks 어댑터의 핵심 리소스 구성 문서예요. 점진적 전략의 일반 개념(merge, insert_overwrite, replace_where 등)과 Databricks 동작 플래그, 그리고 다른 클라우드 어댑터(BigQuery, Snowflake, Redshift)의 구성도 함께 학습하면 dbt의 어댑터별 차이를 훨씬 명확하게 이해할 수 있습니다.