Teradata configurations

Teradata configurations

dbt-teradata 어댑터에서 모델을 구성하는 방법을 다루는 페이지예요. 테이블 옵션, 인덱스, 시드, 스냅샷, grants, query band, valid_history incremental 전략, 외부 테이블 등을 설정할 수 있어요.

출처: 문서

본문

General

  • quote_columns 설정 — 경고를 피하려면 dbt_project.yml에서 quote_columns 값을 명시적으로 설정해야 해요. quote_columns 문서를 참고하세요.
seeds:
  +quote_columns: false  #or `true` if you have CSV column headers with spaces

Models

table

  • table_kind — 테이블 종류를 정의해요. 허용 값은 MULTISET(dbt-teradata가 요구하는 ANSI 트랜잭션 모드의 기본값)과 SET이에요. 예:

SQL materialization 정의 파일에서:

{{
  config(
      materialized="table",
      table_kind="SET"
  )
}}
  • 시드 구성에서:
seeds:
  <project-name>:
    table_kind: "SET"

자세한 내용은 CREATE TABLE 문서를 참고하세요.

table_option — 테이블 옵션을 정의해요. config는 여러 문을 지원해요. 아래 정의는 Teradata 문법 정의를 사용해 어떤 문이 허용되는지 설명해요. 대괄호 []는 선택적 파라미터를 나타내요. 파이프 기호 |는 문을 구분해요. 아래 예시처럼 쉼표로 여러 문을 결합하세요.

{ MAP = map_name [COLOCATE USING colocation_name] |
  [NO] FALLBACK [PROTECTION] |
  WITH JOURNAL TABLE = table_specification |
  [NO] LOG |
  [ NO | DUAL ] [BEFORE] JOURNAL |
  [ NO | DUAL | LOCAL | NOT LOCAL ] AFTER JOURNAL |
  CHECKSUM = { DEFAULT | ON | OFF } |
  FREESPACE = integer [PERCENT] |
  mergeblockratio |
  datablocksize |
  blockcompression |
  isolated_loading
}

여기서:

  • mergeblockratio:
{ DEFAULT MERGEBLOCKRATIO |
  MERGEBLOCKRATIO = integer [PERCENT] |
  NO MERGEBLOCKRATIO
}
  • datablocksize:
DATABLOCKSIZE = {
  data_block_size [ BYTES | KBYTES | KILOBYTES ] |
  { MINIMUM | MAXIMUM | DEFAULT } DATABLOCKSIZE
}
  • blockcompression:
BLOCKCOMPRESSION = { AUTOTEMP | MANUAL | ALWAYS | NEVER | DEFAULT }
  [, BLOCKCOMPRESSIONALGORITHM = { ZLIB | ELZS_H | DEFAULT } ]
  [, BLOCKCOMPRESSIONLEVEL = { value | DEFAULT } ]
  • isolated_loading:
WITH [NO] [CONCURRENT] ISOLATED LOADING [ FOR { ALL | INSERT | NONE } ]

예시:

  • SQL materialization 정의 파일에서:
{{
  config(
      materialized="table",
      table_option="NO FALLBACK"
  )
}}
{{
  config(
      materialized="table",
      table_option="NO FALLBACK, NO JOURNAL"
  )
}}
{{
  config(
      materialized="table",
      table_option="NO FALLBACK, NO JOURNAL, CHECKSUM = ON,
        NO MERGEBLOCKRATIO,
        WITH CONCURRENT ISOLATED LOADING FOR ALL"
  )
}}
  • 시드 구성에서:
seeds:
  <project-name>:
    table_option:"NO FALLBACK"
seeds:
  <project-name>:
    table_option:"NO FALLBACK, NO JOURNAL"
seeds:
  <project-name>:
    table_option: "NO FALLBACK, NO JOURNAL, CHECKSUM = ON,
      NO MERGEBLOCKRATIO,
      WITH CONCURRENT ISOLATED LOADING FOR ALL"

자세한 내용은 CREATE TABLE 문서를 참고하세요.

with_statistics — 기본 테이블에서 통계를 복사할지 여부예요. 예:

{{
  config(
      materialized="table",
      with_statistics="true"
  )
}}

자세한 내용은 CREATE TABLE 문서를 참고하세요.

index — 테이블 인덱스를 정의해요:

[UNIQUE] PRIMARY INDEX [index_name] ( index_column_name [,...] ) |
NO PRIMARY INDEX |
PRIMARY AMP [INDEX] [index_name] ( index_column_name [,...] ) |
PARTITION BY { partitioning_level | ( partitioning_level [,...] ) } |
UNIQUE INDEX [ index_name ] [ ( index_column_name [,...] ) ] [loading] |
INDEX [index_name] [ALL] ( index_column_name [,...] ) [ordering] [loading]
[,...]

여기서:

  • partitioning_level:
{ partitioning_expression |
  COLUMN [ [NO] AUTO COMPRESS |
  COLUMN [ [NO] AUTO COMPRESS ] [ ALL BUT ] column_partition ]
} [ ADD constant ]
  • ordering:
ORDER BY [ VALUES | HASH ] [ ( order_column_name ) ]
  • loading:
WITH [NO] LOAD IDENTITY

예시:

  • SQL materialization 정의 파일에서:
{{
  config(
      materialized="table",
      index="UNIQUE PRIMARY INDEX ( GlobalID )"
  )
}}

ℹ️ 참고: table_option과 달리 index 문 사이에는 쉼표가 없어요!

{{
  config(
      materialized="table",
      index="PRIMARY INDEX(id)
      PARTITION BY RANGE_N(create_date
                    BETWEEN DATE '2020-01-01'
                    AND     DATE '2021-01-01'
                    EACH INTERVAL '1' MONTH)"
  )
}}
{{
  config(
      materialized="table",
      index="PRIMARY INDEX(id)
      PARTITION BY RANGE_N(create_date
                    BETWEEN DATE '2020-01-01'
                    AND     DATE '2021-01-01'
                    EACH INTERVAL '1' MONTH)
      INDEX index_attrA (attrA) WITH LOAD IDENTITY"
  )
}}
  • 시드 구성에서:
seeds:
  <project-name>:
    index: "UNIQUE PRIMARY INDEX ( GlobalID )"

ℹ️ 참고: table_option과 달리 index 문 사이에는 쉼표가 없어요!

seeds:
  <project-name>:
    index: "PRIMARY INDEX(id)
      PARTITION BY RANGE_N(create_date
                    BETWEEN DATE '2020-01-01'
                    AND     DATE '2021-01-01'
                    EACH INTERVAL '1' MONTH)"
seeds:
  <project-name>:
    index: "PRIMARY INDEX(id)
      PARTITION BY RANGE_N(create_date
                    BETWEEN DATE '2020-01-01'
                    AND     DATE '2021-01-01'
                    EACH INTERVAL '1' MONTH)
      INDEX index_attrA (attrA) WITH LOAD IDENTITY"

Seeds

원시 데이터 로딩에 시드 사용 — dbt seeds 문서에서 설명하듯이, 시드는 원시 데이터(예: 프로덕션 데이터베이스의 대용량 CSV 내보내기)를 로딩하는 데 쓰면 안 돼요. 시드는 버전 관리되므로 국가 코드 목록이나 직원 user ID 같은 비즈니스 특정 로직이 담긴 파일에 가장 적합해요.

dbt의 seed 기능으로 CSV를 로딩하는 것은 대용량 파일에 성능이 좋지 않아요. 이런 CSV를 데이터 웨어하우스에 로딩할 때는 다른 도구를 사용하는 것을 고려하세요.

  • use_fastloaddbt seed 명령 처리 시 fastload 사용 여부예요. 시드 파일에 수십만 행이 있으면 로딩이 빨라질 가능성이 있어요. 이 시드 구성 옵션은 project.yml 파일에서 설정할 수 있어요. 예:
seeds:
  <project-name>:
    +use_fastload: true

Snapshots

스냅샷은 Teradata 데이터베이스의 HASHROW 함수를 사용해 dbt_scd_id 컬럼의 고유 해시 값을 생성해요.

나만의 해시 UDF를 쓰려면 스냅샷 모델에 snapshot_hash_udf라는 구성 옵션이 있는데, 기본값은 HASHROW예요. `` 같은 값을 제공할 수 있어요. hash_udf_name만 제공하면 모델이 실행되는 것과 같은 스키마를 사용해요.

예를 들어 snapshots/snapshot_example.sql 파일에서:

{% snapshot snapshot_example %}
{{
  config(
    target_schema='snapshots',
    unique_key='id',
    strategy='check',
    check_cols=["c2"],
    snapshot_hash_udf='GLOBAL_FUNCTIONS.hash_md5'
  )
}}
select * from {{ ref('order_payments') }}
{% endsnapshot %}

Grants

Grants는 dbt-teradata 어댑터에서 1.2.0 이상 릴리스부터 지원돼요. grants로 dbt로 만드는 데이터셋에 대한 접근을 관리할 수 있어요. 이 권한을 구현하려면 각 모델, 시드, 스냅샷에 리소스 config로 grants를 정의해요. dbt_project.yml에서 프로젝트 전체에 적용되는 기본 grants를 정의하고, 각 모델의 SQL 또는 property 파일 안에서 모델별 grants를 정의해요.

예:

models/schema.yml

models:
  - name: model_name
    config:
      grants:
        select: ['user_a', 'user_b']

여러 grants를 추가하는 또 다른 예시:

models:
- name: model_name
  config:
    materialized: table
    grants:
      select: ["user_b"]
      insert: ["user_c"]

ℹ️ copy_grants는 Teradata에서 지원되지 않아요.

Grants에 대한 자세한 내용은 grants를 참고하세요.

Query band

dbt-teradata의 query band는 세 가지 레벨에서 설정할 수 있어요.

  1. Profiles 레벨: profiles.yml 파일에서 다음 예시처럼 query_band를 제공할 수 있어요.
query_band: 'application=dbt;'
  1. Project 레벨: dbt_project.yml 파일에서 다음 예시처럼 query_band를 제공할 수 있어요.
models:
  Project_name:
     +query_band: "app=dbt;model={model};"
  1. Model 레벨: 모델 SQL 파일 또는 YAML 파일의 모델 레벨 구성에서 설정할 수 있어요.
{{ config( query_band='sql={model};' ) }}

사용자는 어떤 레벨이든, 모든 레벨에 query_band를 설정할 수 있어요. profiles 레벨 query_band로 dbt-teradata는 세션에 대해 처음으로 query_band를 설정하고, 이후 model과 project 레벨 query band는 각 구성에 따라 갱신돼요.

값이 '{model}'인 키-값 쌍을 설정하면 내부적으로 이 '{model}'이 모델 이름으로 치환돼요. sql/dbql 로깅의 텔레메트리 추적에 유용할 수 있어요.

models:
Project_name:
  +query_band: "app=dbt;model={model};"
  • 예를 들어 사용자가 실행하는 모델이 stg_orders라면 런타임에 {model}stg_orders로 치환돼요.
  • 사용자가 query_band를 설정하지 않으면 기본 query_band는 org=teradata-internal-telem;appname=dbt;예요.

Unit testing

  • 단위 테스트는 dbt-teradata에서 지원되며, 사용자가 dbt test 명령으로 단위 테스트를 작성·실행할 수 있어요.

자세한 지침은 dbt unit tests 문서를 참고하세요.

Teradata에서는 단일 모델 안에서 여러 공통 테이블 표현식(CTE)이나 서브쿼리에서 같은 별칭을 재사용할 수 없어요. 파싱 오류가 나기 때문이에요. 그래서 각 CTE나 서브쿼리에 고유한 별칭을 지정해 제대로 실행되도록 하는 것이 필수적이에요.

valid_history incremental materialization strategy

얼리 액세스로 제공

이 전략은 Teradata 환경에서 과거 데이터를 효율적으로 관리하도록 설계됐어요. dbt 기능을 활용해 데이터 품질과 최적의 리소스 사용을 보장해요. 시간 기반(temporal) 데이터베이스에서 유효 시간(valid time)은 과거 보고, ML 훈련 데이터셋, 포렌식 분석 같은 애플리케이션에 중요해요.

{{
      config(
          materialized='incremental',
          unique_key='id',
          on_schema_change='fail',
          incremental_strategy='valid_history',
          valid_period='valid_period_col',
          use_valid_to_time='no',
  )
  }}

valid_history incremental 전략은 다음 파라미터를 요구해요.

  • unique_key: 모델의 기본 키(유효 시간 구성 요소 제외), 컬럼 이름 또는 컬럼 이름 목록으로 지정.
  • valid_period: 레코드가 유효한 기간을 나타내는 모델 컬럼 이름. 데이터 타입은 PERIOD(DATE) 또는 PERIOD(TIMESTAMP)여야 해요.
  • use_valid_to_time: 유효 시간선을 만들 때 전략이 입력의 유효 기간 끝 경계 값을 고려할지 여부. 레코드가 바뀔 때까지 유효하다고 본다면 no를 쓰세요(그리고 기간의 끝 경계에 대해 시작 경계보다 큰 값을 제공하세요. 일반적인 관례는 9999-12-31 또는 9999-12-31 23:59:59.999999). 레코드가 언제까지 유효한지 안다면 yes를 쓰세요 (보통 이력 시간선의 수정입니다).

dbt-teradata의 valid_history 전략은 과거 데이터 관리의 무결성과 정확성을 보장하기 위해 몇 가지 핵심 단계를 수반해요.

  • 소스 데이터에서 중복과 충돌 값을 제거:

이 단계는 모델이 만든 데이터셋에서 중복되거나 충돌하는 레코드를 제거해 데이터를 깨끗하고 추가 처리 준비가 되게 해요.

  • 기본 키 중복(같은 unique_key 값과 valid_period 필드의 BEGIN() 경계를 가진 두 개 이상의 레코드)을 제거하는 과정. 이런 중복이 있으면 모든 비-기본 키 필드에 대해 가장 낮은 값을 가진 행이 유지돼요 (모델에 지정된 순서대로). 전체 행 중복은 항상 중복 제거돼요.

겹치거나 인접한 시간 슬라이스 식별·조정:

  • 데이터의 겹치거나 인접한 시간 기간은 일관되고 겹치지 않는 시간선을 유지하도록 수정돼요. 이를 위해 매크로는 같은 unique_key 그룹 안에서 레코드의 유효 기간 끝 경계를 다음 레코드의 시작 경계에 맞춰 조정해요(겹치거나 인접한 경우). use_valid_to_time = 'yes'면 소스 데이터에 제공된 유효 기간 끝 경계가 사용돼요. 그렇지 않으면 누락된 경계에 기본 종료일이 적용되고 그에 따라 조정돼요.

소스와 대상 데이터를 기반으로 조정·삭제·분할이 필요한 레코드 관리:

  • 소스 데이터의 레코드가 대상 데이터의 레코드와 겹치거나 이를 교체해야 하는 시나리오를 처리해, 이력 시간선이 정확하게 유지되도록 해요.

이력 압축:

  • 같은 값을 가진 인접 시간 기간의 레코드를 병합해 이력을 정규화·압축해, 데이터베이스 저장 공간과 성능을 최적화해요. 이를 위해 TD_NORMALIZE_MEET 함수를 사용해요.

대상 테이블에서 기존 겹치는 레코드 삭제:

  • 새 레코드나 갱신된 레코드를 삽입하기 전에, 대상 테이블의 새 데이터와 겹치는 기존 레코드를 제거해 충돌을 방지해요.

처리된 데이터를 대상 테이블에 삽입:

  • 마지막으로 정리·조정된 데이터가 대상 테이블에 삽입되어, 이력 데이터가 최신 상태이고 의도된 시간선을 정확히 반영하도록 해요.

이 단계들은 collectively하게 valid_history 전략이 이력 데이터를 효과적으로 관리하고, 무결성·정확성을 유지하면서 성능을 최적화하도록 보장해요.

소스 샘플 데이터와 그에 해당하는 대상 데이터를 보여주는 예시:

  -- Source data
      pk |       valid_from          | value_txt1 | value_txt2
      ======================================================================
      1  | 2024-03-01 00:00:00.0000  | A          | x1
      1  | 2024-03-12 00:00:00.0000  | B          | x1
      1  | 2024-03-12 00:00:00.0000  | B          | x2
      1  | 2024-03-25 00:00:00.0000  | A          | x2
      2  | 2024-03-01 00:00:00.0000  | A          | x1
      2  | 2024-03-12 00:00:00.0000  | C          | x1
      2  | 2024-03-12 00:00:00.0000  | D          | x1
      2  | 2024-03-13 00:00:00.0000  | C          | x1
      2  | 2024-03-14 00:00:00.0000  | C          | x1

  -- Target data
      pk | valid_period                                                       | value_txt1 | value_txt2
      ===================================================================================================
      1  | PERIOD(TIMESTAMP)[2024-03-01 00:00:00.0, 2024-03-12 00:00:00.0]    | A          | x1
      1  | PERIOD(TIMESTAMP)[2024-03-12 00:00:00.0, 2024-03-25 00:00:00.0]    | B          | x1
      1  | PERIOD(TIMESTAMP)[2024-03-25 00:00:00.0, 9999-12-31 23:59:59.9999] | A          | x2
      2  | PERIOD(TIMESTAMP)[2024-03-01 00:00:00.0, 2024-03-12 00:00:00.0]    | A          | x1
      2  | PERIOD(TIMESTAMP)[2024-03-12 00:00:00.0, 9999-12-31 23:59:59.9999] | C          | x1

Common Teradata-specific tasks

  • 통계 수집 — 테이블이 생성되거나 크게 수정되면, Teradata에 옵티마이저를 위한 통계 수집을 알려야 할 때가 있어요. COLLECT STATISTICS 명령으로 할 수 있어요. 이 단계는 dbt의 post-hooks로 수행할 수 있어요. 예:
{{ config(
  post_hook=[
    "COLLECT STATISTICS ON  {{ this }} COLUMN (column_1,  column_2  ...);"
    ]
)}}

자세한 내용은 Collecting Statistics 문서를 참고하세요.

The external tables package

dbt-external-tables 패키지는 dbt-teradata 어댑터에서 v1.9.3부터 지원돼요. 내부적으로 dbt-teradata는 외부 소스에서 테이블을 만들기 위해 foreign tables 개념을 사용해요. 자세한 내용은 Teradata 문서에서 찾을 수 있어요.

의존성으로 dbt-external-tables 패키지를 추가해야 해요.

packages:
  - package: dbt-labs/dbt_external_tables
    version: [">=0.9.0", "<1.0.0"]

프로젝트가 dbt-teradata 패키지의 재정의된 매크로를 선택하도록 dispatch config를 추가해야 해요.

dispatch:
  - macro_namespace: dbt_external_tables
    search_order: ['dbt', 'dbt_external_tables']

외부 테이블의 STOREDASROWFORMAT를 정의하려면 다음 옵션 중 하나를 쓸 수 있어요.

  • 표준 dbt-external-tables config인 file_formatrow_format을 각각 사용.
  • 또는 Teradata 문서에 언급된 대로 USING config에 추가.

인증이 필요한 외부 소스의 경우 인증 객체를 만들어 tbl_properties에서 EXTERNAL SECURITY 객체로 전달해야 해요. 인증 객체에 대한 자세한 내용은 Teradata 문서를 확인하세요.

다음은 Teradata에 구성된 외부 소스 예시예요.

sources:
  - name: teradata_external
    schema: "{{ target.schema }}"
    loader: S3

    tables:
      - name: people_csv_partitioned
        external:
          location: "/s3/s3.amazonaws.com/dbt-external-tables-testing/csv/"
          file_format: "TEXTFILE"
          row_format: '{"field_delimiter":",","record_delimiter":"\n","character_set":"LATIN"}'
          using: |
            PATHPATTERN  ('$var1/$section/$var3')
          tbl_properties: |
            MAP = TD_MAP1
            ,EXTERNAL SECURITY  MyAuthObj
          partitions:
            - name: section
              data_type: CHAR(1)
        columns:
          - name: id
            data_type: int
          - name: first_name
            data_type: varchar(64)
          - name: last_name
            data_type: varchar(64)
          - name: email
            data_type: varchar(64)
sources:
  - name: teradata_external
    schema: "{{ target.schema }}"
    loader: S3

    tables:
      - name: people_json_partitioned
        external:
          location: '/s3/s3.amazonaws.com/dbt-external-tables-testing/json/'
          using: |
            STOREDAS('TEXTFILE')
            ROWFORMAT('{"record_delimiter":"\n", "character_set":"cs_value"}')
            PATHPATTERN  ('$var1/$section/$var3')
          tbl_properties: |
            MAP = TD_MAP1
            ,EXTERNAL SECURITY  MyAuthObj
          partitions:
            - name: section
              data_type: CHAR(1)

temporary_metadata_generation_schema (이전 fallback_schema)

dbt-teradata 어댑터는 manifest와 catalog 생성을 위해 뷰의 메타데이터를 가져올 때 내부적으로 임시 테이블을 만들어요. 작업 중인 스키마에 테이블을 만들 권한이 없다면, dbt_project.yml에서 변수로 temporary_metadata_generation_schema(적절한 create/drop 권한이 있는)를 정의할 수 있어요.

vars:
  temporary_metadata_generation_schema: <schema-name>

더 알아보기 (Learn more)