- dbt 프로젝트를 생성하고 ClickHouse 어댑터를 설정합니다.
- 모델을 정의합니다.
- 모델을 업데이트합니다.
- 증분 모델을 생성합니다.
- 스냅샷 모델을 생성합니다.
- materialized view를 사용합니다.
설정
ClickHouse 준비
테이블
roles의 created_at 컬럼 기본값은 now()입니다. 이는 나중에 모델의 증분 업데이트를 식별하는 데 사용합니다. 자세한 내용은 증분 모델을 참조하십시오.s3 함수를 사용해 공개 엔드포인트에서 소스 데이터를 읽습니다. 테이블을 채우려면 다음 명령을 실행하세요:
ClickHouse에 연결하기
-
dbt 프로젝트를 생성합니다. 여기서는
imdb소스의 이름을 따서 프로젝트 이름을 지정합니다. 프롬프트가 표시되면 데이터베이스 소스로clickhouse를 선택합니다. -
프로젝트 폴더로 이동합니다.
- 이제 원하는 텍스트 편집기가 필요합니다. 아래 예시에서는 널리 사용되는 VS Code를 사용합니다. IMDB 디렉터리를 열면 yml 파일과 sql 파일이 있는 것을 확인할 수 있습니다.
-
dbt_project.yml파일을 업데이트하여 첫 번째 model인actor_summary를 지정하고, profile을clickhouse_imdb로 설정합니다. -
다음으로 dbt에 ClickHouse 인스턴스의 연결 정보를 제공해야 합니다. 아래 내용을
~/.dbt/profiles.yml에 추가합니다.user와password는 환경에 맞게 수정해야 합니다. 추가로 사용할 수 있는 설정은 여기에 문서화되어 있습니다. -
IMDB 디렉터리에서
dbt debug명령을 실행하여 dbt가 ClickHouse에 연결할 수 있는지 확인합니다.응답에Connection test: [OK connection ok]가 포함되어 있는지 확인하십시오. 이는 연결이 성공했음을 의미합니다.
간단한 뷰 머티리얼라이즈 만들기
CREATE VIEW AS 구문을 통해 뷰로 다시 생성됩니다. 이 방식은 데이터를 추가로 저장할 필요는 없지만, 테이블 머티리얼라이즈보다 쿼리 성능이 느립니다.
-
imdb폴더에서models/example디렉터리를 삭제하십시오: -
models폴더의actors내에 새 파일을 만드세요. 여기서는 각 파일이 하나의 actor 모델을 나타내도록 생성합니다: -
models/actors폴더에schema.yml과actor_summary.sql파일을 생성하세요.파일schema.yml에서 테이블을 정의합니다. 이렇게 정의한 테이블은 이후 매크로에서 사용할 수 있습니다. Editmodels/actors/schema.yml파일을 편집하여 다음 내용을 포함하도록 하세요:actors_summary.sql은 실제 model을 정의합니다. config 함수에서는 이 model이 ClickHouse에서 뷰로 구체화되도록 요청한다는 점에 유의하십시오. 테이블은schema.yml파일에서source함수를 통해 참조합니다. 예를 들어source('imdb', 'movies')는imdb데이터베이스의movies테이블을 가리킵니다.models/actors/actors_summary.sql을 편집하여 다음 내용을 포함하도록 하십시오:최종 actor_summary에updated_at컬럼을 포함했다는 점에 유의하십시오. 이는 이후 증분 머티리얼라이제이션에 사용됩니다. -
imdb디렉터리에서dbt run명령을 실행하세요. -
dbt는 요청한 대로 model을 ClickHouse의 뷰로 생성합니다. 이제 이 뷰에 직접 쿼리할 수 있습니다. 이 뷰는
imdb_dbt데이터베이스에 생성되며, 이는clickhouse_imdbprofile 아래~/.dbt/profiles.yml파일의 스키마(schema) 매개변수로 결정됩니다.이 뷰를 쿼리하면 더 간단한 구문으로 앞서 실행한 쿼리의 결과를 재현할 수 있습니다:
테이블 머티리얼라이즈 생성하기
INSERT TO SELECT가 실행됩니다. 이 테이블은 매번 다시 생성되며, 다시 말해 증분 방식이 아닙니다. 따라서 큰 결과 집합은 실행 시간이 길어질 수 있습니다. 자세한 내용은 dbt 제한 사항을 참조하십시오.
-
actors_summary.sql파일을 수정하여materialized매개변수를table로 설정합니다.ORDER BY가 어떻게 정의되어 있는지와MergeTree테이블 엔진을 사용한다는 점에 주목하십시오: -
imdb디렉터리에서dbt run명령을 실행합니다. 이 작업은 완료까지 약간 더 오래 걸릴 수 있으며, 대부분의 환경에서 약 10초 정도 소요됩니다. -
imdb_dbt.actor_summary테이블이 생성되었는지 확인합니다:적절한 데이터 타입으로 정의된 테이블이 표시되어야 합니다: -
이 테이블의 결과가 이전 응답과 일치하는지 확인합니다. 이제 모델이 테이블로 구체화되었으므로 응답 시간이 눈에 띄게 개선된 것을 확인할 수 있습니다:
이 모델에 대해 다른 쿼리도 자유롭게 실행해 보십시오. 예를 들어, 5편을 초과해 출연한 배우 중 평균 평점이 가장 높은 배우는 누구인지 확인할 수 있습니다.
증분 머티리얼라이즈 생성하기
-
먼저 model을 incremental 유형으로 변경합니다. 이를 추가하려면 다음이 필요합니다:
- unique_key - 어댑터가 행을 고유하게 식별할 수 있도록 unique_key를 제공해야 합니다. 이 경우 쿼리의
id필드면 충분합니다. 이렇게 하면 구체화된 테이블(Materialized Table)에 중복 행이 생기지 않습니다. 고유성 제약 조건에 관한 자세한 내용은 여기를 참조하십시오. - Incremental filter - 또한 증분 실행 시 변경된 행을 dbt가 어떻게 식별할지 지정해야 합니다. 이는 델타 표현식을 제공해 구현합니다. 일반적으로 이벤트 데이터에는 타임스탬프를 사용하므로, 여기서는 updated_at 타임스탬프 필드를 사용합니다. 이 컬럼은 행이 삽입될 때 기본값으로 now()를 사용하므로 새로운 역할을 식별할 수 있습니다. 또한 새 액터가 추가되는 경우도 식별해야 합니다. 기존 구체화된 테이블을 나타내는
{{this}}변수를 사용하면where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})라는 표현식을 만들 수 있습니다. 이 표현식은{% if is_incremental() %}조건 안에 넣어 테이블을 처음 생성할 때가 아니라 증분 실행에서만 사용되도록 합니다. 증분 모델에서 행을 필터링하는 방법에 관한 자세한 내용은 dbt 문서의 이 설명을 참조하십시오.
actor_summary.sql파일을 다음과 같이 수정하십시오:이 모델은roles및actors테이블의 업데이트와 추가에만 반응합니다. 모든 테이블에 반응하도록 하려면 이 모델을 여러 개의 하위 모델로 나누고, 각 하위 모델에 자체 증분 기준을 설정하는 것이 좋습니다. 이후 이러한 모델은 서로 참조하고 연결할 수 있습니다. 모델 간 교차 참조에 대한 자세한 내용은 here를 참조하십시오. - unique_key - 어댑터가 행을 고유하게 식별할 수 있도록 unique_key를 제공해야 합니다. 이 경우 쿼리의
-
dbt run을 실행하고 생성된 테이블의 결과를 확인합니다: -
이제 증분 업데이트를 보여주기 위해 모델에 데이터를 추가하겠습니다.
actors테이블에 배우 “Clicky McClickHouse”를 추가하세요: -
“Clicky”가 무작위로 선택된 영화 910편에 출연하게 해보겠습니다:
-
기반이 되는 원본 테이블을 직접 쿼리해 dbt 모델을 거치지 않고, 이제 그가 실제로 가장 많이 출연한 배우인지 확인합니다:
-
dbt run을 실행한 뒤 모델이 업데이트되어 위의 결과와 일치하는지 확인하세요:
내부 동작
- 어댑터는 임시 테이블
actor_sumary__dbt_tmp를 생성합니다. 변경된 행은 이 테이블로 스트리밍됩니다. - 새 테이블
actor_summary_new,를 생성합니다. 그런 다음 이전 테이블의 행을 이전 테이블에서 새 테이블로 스트리밍하면서, 행 ID가 임시 테이블에 존재하지 않는지 확인합니다. 이렇게 하면 업데이트와 중복을 효과적으로 처리할 수 있습니다. - 임시 테이블의 결과를 새
actor_summary테이블로 스트리밍합니다: - 마지막으로
EXCHANGE TABLES구문을 통해 새 테이블을 이전 버전과 원자적으로 교환합니다. 이후 이전 테이블과 임시 테이블을 삭제합니다.
Append Strategy (삽입 전용 모드)
incremental_strategy를 사용합니다. 이 매개변수는 append 값으로 설정할 수 있습니다. 이렇게 설정하면 업데이트된 행이 대상 테이블(즉, imdb_dbt.actor_summary)에 직접 삽입되고, 임시 테이블은 생성되지 않습니다.
참고: Append only 모드를 사용하려면 데이터가 불변이어야 하거나 중복이 허용되어야 합니다. 변경된 행을 지원하는 증분 테이블 모델이 필요하다면 이 모드를 사용하지 마십시오.
이 모드를 설명하기 위해 새 배우를 한 명 더 추가한 다음, incremental_strategy='append'로 dbt run을 다시 실행하겠습니다.
-
actor_summary.sql에서 append only 모드를 구성합니다:
-
유명한 배우를 한 명 더 추가합니다. Danny DeBito입니다.
-
Danny를 무작위 영화 920편에 출연시킵니다.
-
dbt run을 실행하고 actor-summary 테이블에 Danny가 추가되었는지 확인합니다.
imdb_dbt.actor_summary 테이블에 바로 추가되고, 테이블은 생성되지 않습니다.
삭제 및 삽입 모드(실험적)
incremental_strategy 매개변수로 구성할 수 있습니다. 즉,
- 어댑터가 임시 테이블
actor_sumary__dbt_tmp를 생성합니다. 변경된 행은 이 테이블로 스트리밍됩니다. - 현재
actor_summary테이블에DELETE를 실행합니다.actor_sumary__dbt_tmp의 id를 기준으로 행을 삭제합니다. actor_sumary__dbt_tmp의 행을INSERT INTO actor_summary SELECT * FROM actor_sumary__dbt_tmp를 사용해actor_summary에 삽입합니다.
insert_overwrite 모드 (실험적)
- 증분 모델 릴레이션과 동일한 구조의 스테이징(임시) 테이블을 생성합니다:
CREATE TABLE {staging} AS {target}. - 새 레코드만(SELECT로 생성된 레코드) 스테이징 테이블에 삽입합니다.
- 새 파티션만(스테이징 테이블에 있는 파티션) 대상 테이블로 교체합니다.
이 접근 방식에는 다음과 같은 장점이 있습니다:
- 전체 테이블을 복사하지 않으므로 기본 전략보다 더 빠릅니다.
- INSERT 작업이 성공적으로 완료될 때까지 원본 테이블을 수정하지 않으므로 다른 전략보다 더 안전합니다. 중간에 실패하더라도 원본 테이블은 수정되지 않습니다.
- 데이터 엔지니어링 모범 사례인 “파티션 불변성”을 구현합니다. 따라서 증분 및 병렬 데이터 처리, 롤백 등이 더 단순해집니다.
스냅샷 생성
inserts_only=True를 설정하지 마십시오. models/actor_summary.sql은 다음과 같아야 합니다:
-
snapshots디렉터리에actor_summary파일을 생성합니다. -
actor_summary.sql 파일의 내용을 다음과 같이 업데이트합니다.
- select 쿼리는 시간에 따라 스냅샷으로 저장할 결과를 정의합니다.
ref함수는 앞서 생성한 actor_summary 모델을 참조하는 데 사용됩니다. - 레코드 변경을 나타내려면
timestamp컬럼이 필요합니다. 여기서는 updated_at 컬럼(증분 테이블 모델 생성 참고)을 사용할 수 있습니다.strategy매개변수는 업데이트를 표시하는 데timestamp를 사용함을 의미하며,updated_at매개변수는 사용할 컬럼을 지정합니다. 모델에 이 컬럼이 없다면 대신 check strategy를 사용할 수도 있습니다. 이 방법은 훨씬 비효율적이며, 비교할 컬럼 목록을 사용자가 직접 지정해야 합니다. dbt는 이 컬럼들의 현재 값과 과거 값을 비교해 변경 사항을 기록합니다(값이 같으면 아무 작업도 수행하지 않음).
-
dbt snapshot명령을 실행합니다.
actor_summary_snapshot 테이블이 snapshots DB에 생성된 것을 확인할 수 있습니다. 이는 target_schema 매개변수로 결정됩니다.
-
이 데이터를 샘플링해 보면 dbt가 dbt_valid_from 및 dbt_valid_to 컬럼을 포함했음을 확인할 수 있습니다. 후자의 값은 NULL로 설정되어 있습니다. 이후 실행에서 이 값이 업데이트됩니다.
-
가장 좋아하는 배우 Clicky McClickHouse가 영화 10편에 더 출연하도록 하세요.
-
imdb디렉터리에서dbt run명령을 다시 실행하세요. 그러면 증분 모델이 업데이트됩니다. 이 작업이 완료되면 변경 사항을 기록하기 위해dbt snapshot을 실행하세요. -
이제 스냅샷을 쿼리하면 Clicky McClickHouse에 대한 행이 2개 있는 것을 확인할 수 있습니다. 이전 항목에는 이제 dbt_valid_to 값이 설정되어 있습니다. 새 값은 dbt_valid_from 컬럼에 동일한 값으로 기록되고, dbt_valid_to 값은 null입니다. 새 행이 있었다면 이 역시 스냅샷에 추가되었을 것입니다.
seed 사용하기
-
기존 데이터셋에서 장르 코드 목록을 생성합니다. dbt 디렉터리에서
clickhouse-client를 사용해seeds/genre_codes.csv파일을 만드십시오. -
dbt seed명령을 실행합니다. 그러면 데이터베이스imdb_dbt에 새 테이블genre_codes가 생성되고(이는 schema 구성에 정의되어 있음), CSV 파일의 행이 이 테이블에 로드됩니다. -
데이터가 로드되었는지 확인합니다: