이 섹션에서는 dbt와 ClickHouse 어댑터를 설정하는 가이드와, 공개적으로 제공되는 IMDB 데이터셋을 사용해 ClickHouse에서 dbt를 사용하는 예시를 제공합니다. 이 예시에서는 다음 단계를 다룹니다:
- dbt 프로젝트를 생성하고 ClickHouse 어댑터를 설정합니다.
- 모델을 정의합니다.
- 모델을 업데이트합니다.
- 증분 모델을 생성합니다.
- 스냅샷 모델을 생성합니다.
- materialized view를 사용합니다.
이 가이드는 문서, 기능 및 구성, materializations 참고와 함께 사용할 수 있도록 작성되었습니다.
설정
환경을 준비하려면 dbt 및 ClickHouse 어댑터 설정 섹션의 안내를 따르십시오.
중요: 아래 내용은 Python 3.9 환경에서 테스트되었습니다.
ClickHouse 준비
dbt는 고도로 관계형인 데이터를 모델링하는 데 매우 적합합니다. 예시를 위해 아래와 같은 관계형 스키마를 가진 소규모 IMDB 데이터셋을 제공합니다. 이 데이터셋은 관계형 데이터셋 리포지토리에서 가져왔습니다. 이는 dbt와 함께 일반적으로 사용하는 스키마와 비교하면 매우 단순하지만, 다루기 쉬운 예시로는 적절합니다.

표시된 것처럼 이들 테이블의 부분 집합을 사용합니다.
다음 테이블을 생성하십시오:
CREATE DATABASE imdb;
CREATE TABLE imdb.actors
(
id UInt32,
first_name String,
last_name String,
gender FixedString(1)
) ENGINE = MergeTree ORDER BY (id, first_name, last_name, gender);
CREATE TABLE imdb.directors
(
id UInt32,
first_name String,
last_name String
) ENGINE = MergeTree ORDER BY (id, first_name, last_name);
CREATE TABLE imdb.genres
(
movie_id UInt32,
genre String
) ENGINE = MergeTree ORDER BY (movie_id, genre);
CREATE TABLE imdb.movie_directors
(
director_id UInt32,
movie_id UInt64
) ENGINE = MergeTree ORDER BY (director_id, movie_id);
CREATE TABLE imdb.movies
(
id UInt32,
name String,
year UInt32,
rank Float32 DEFAULT 0
) ENGINE = MergeTree ORDER BY (id, name, year);
CREATE TABLE imdb.roles
(
actor_id UInt32,
movie_id UInt32,
role String,
created_at DateTime DEFAULT now()
) ENGINE = MergeTree ORDER BY (actor_id, movie_id);데이터를 삽입하기 위해 s3 함수를 사용해 공개 엔드포인트에서 소스 데이터를 읽습니다. 테이블을 채우려면 다음 명령을 실행하세요:
INSERT INTO imdb.actors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_actors.tsv.gz', NOSIGN,
'TSVWithNames');
INSERT INTO imdb.directors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_directors.tsv.gz', NOSIGN,
'TSVWithNames');
INSERT INTO imdb.genres
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies_genres.tsv.gz', NOSIGN,
'TSVWithNames');
INSERT INTO imdb.movie_directors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies_directors.tsv.gz', NOSIGN,
'TSVWithNames');
INSERT INTO imdb.movies
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies.tsv.gz', NOSIGN,
'TSVWithNames');
INSERT INTO imdb.roles(actor_id, movie_id, role)
SELECT actor_id, movie_id, role
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_roles.tsv.gz', NOSIGN,
'TSVWithNames');실행 시간은 사용 중인 대역폭에 따라 달라질 수 있지만, 각 작업은 완료까지 몇 초밖에 걸리지 않습니다. 다음 쿼리를 실행하여 영화 출연 횟수 순으로 각 배우의 요약을 계산하고, 데이터가 성공적으로 로드되었는지 확인하십시오:
SELECT id,
any(actor_name) AS name,
uniqExact(movie_id) AS num_movies,
avg(rank) AS avg_rank,
uniqExact(genre) AS unique_genres,
uniqExact(director_name) AS uniq_directors,
max(created_at) AS updated_at
FROM (
SELECT imdb.actors.id AS id,
concat(imdb.actors.first_name, ' ', imdb.actors.last_name) AS actor_name,
imdb.movies.id AS movie_id,
imdb.movies.rank AS rank,
genre,
concat(imdb.directors.first_name, ' ', imdb.directors.last_name) AS director_name,
created_at
FROM imdb.actors
JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id
LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id
LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id
LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id
LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id
)
GROUP BY id
ORDER BY num_movies DESC
LIMIT 5;응답은 다음과 같아야 합니다:
+------+------------+----------+------------------+-------------+--------------+-------------------+
|id |name |num_movies|avg_rank |unique_genres|uniq_directors|updated_at |
+------+------------+----------+------------------+-------------+--------------+-------------------+
|45332 |Mel Blanc |832 |6.175853582979779 |18 |84 |2022-04-26 14:01:45|
|621468|Bess Flowers|659 |5.57727638854796 |19 |293 |2022-04-26 14:01:46|
|372839|Lee Phelps |527 |5.032976449684617 |18 |261 |2022-04-26 14:01:46|
|283127|Tom London |525 |2.8721716524875673|17 |203 |2022-04-26 14:01:46|
|356804|Bud Osborne |515 |2.0389507108727773|15 |149 |2022-04-26 14:01:46|
+------+------------+----------+------------------+-------------+--------------+-------------------+이후 가이드에서는 이 쿼리를 모델로 변환한 뒤, ClickHouse에서 dbt 뷰와 테이블로 구체화합니다.
ClickHouse에 연결하기
-
dbt 프로젝트를 생성합니다. 여기서는
imdb소스의 이름을 따서 프로젝트 이름을 지정합니다. 프롬프트가 표시되면 데이터베이스 소스로clickhouse를 선택합니다.clickhouse-user@clickhouse:~$ dbt init imdb 16:52:40 Running with dbt=1.1.0 Which database would you like to use? [1] clickhouse (Don't see the one you want? https://docs.getdbt.com/docs/available-adapters) Enter a number: 1 16:53:21 No sample profile found for clickhouse. 16:53:21 Your new dbt project "imdb" was created! For more information on how to configure the profiles.yml file, please consult the dbt documentation here: https://docs.getdbt.com/docs/configure-your-profile -
프로젝트 폴더로 이동합니다.
cd imdb -
이제 원하는 텍스트 편집기가 필요합니다. 아래 예시에서는 널리 사용되는 VS Code를 사용합니다. IMDB 디렉터리를 열면 yml 파일과 sql 파일이 있는 것을 확인할 수 있습니다.

-
dbt_project.yml파일을 업데이트하여 첫 번째 model인actor_summary를 지정하고, profile을clickhouse_imdb로 설정합니다.

-
다음으로 dbt에 ClickHouse 인스턴스의 연결 정보를 제공해야 합니다. 아래 내용을
~/.dbt/profiles.yml에 추가합니다.clickhouse_imdb: target: dev outputs: dev: type: clickhouse schema: imdb_dbt host: localhost port: 8123 user: default password: '' secure: Falseuser와password는 환경에 맞게 수정해야 합니다. 추가로 사용할 수 있는 설정은 여기에 문서화되어 있습니다. -
IMDB 디렉터리에서
dbt debug명령을 실행하여 dbt가 ClickHouse에 연결할 수 있는지 확인합니다.clickhouse-user@clickhouse:~/imdb$ dbt debug 17:33:53 Running with dbt=1.1.0 dbt version: 1.1.0 python version: 3.10.1 python path: /home/dale/.pyenv/versions/3.10.1/bin/python3.10 os info: Linux-5.13.0-10039-tuxedo-x86_64-with-glibc2.31 Using profiles.yml file at /home/dale/.dbt/profiles.yml Using dbt_project.yml file at /opt/dbt/imdb/dbt_project.yml Configuration: profiles.yml file [OK found and valid] dbt_project.yml file [OK found and valid] Required dependencies: - git [OK found] Connection: host: localhost port: 8123 user: default schema: imdb_dbt secure: False verify: False Connection test: [OK connection ok] All checks passed!응답에
Connection test: [OK connection ok]가 포함되어 있는지 확인하십시오. 이는 연결이 성공했음을 의미합니다.
간단한 뷰 머티리얼라이즈 만들기
뷰 머티리얼라이즈를 사용하면 모델은 실행할 때마다 ClickHouse의 CREATE VIEW AS 구문을 통해 뷰로 다시 생성됩니다. 이 방식은 데이터를 추가로 저장할 필요는 없지만, 테이블 머티리얼라이즈보다 쿼리 성능이 느립니다.
-
imdb폴더에서models/example디렉터리를 삭제하십시오:clickhouse-user@clickhouse:~/imdb$ rm -rf models/example -
models폴더의actors내에 새 파일을 만드세요. 여기서는 각 파일이 하나의 actor 모델을 나타내도록 생성합니다:clickhouse-user@clickhouse:~/imdb$ mkdir models/actors -
models/actors폴더에schema.yml과actor_summary.sql파일을 생성하세요.clickhouse-user@clickhouse:~/imdb$ touch models/actors/actor_summary.sql clickhouse-user@clickhouse:~/imdb$ touch models/actors/schema.yml파일
schema.yml에서 테이블을 정의합니다. 이렇게 정의한 테이블은 이후 매크로에서 사용할 수 있습니다. Editmodels/actors/schema.yml파일을 편집하여 다음 내용을 포함하도록 하세요:version: 2 sources: - name: imdb tables: - name: directors - name: actors - name: roles - name: movies - name: genres - name: movie_directorsactors_summary.sql은 실제 model을 정의합니다. config 함수에서는 이 model이 ClickHouse에서 뷰로 구체화되도록 요청한다는 점에 유의하십시오. 테이블은schema.yml파일에서source함수를 통해 참조합니다. 예를 들어source('imdb', 'movies')는imdb데이터베이스의movies테이블을 가리킵니다.models/actors/actors_summary.sql을 편집하여 다음 내용을 포함하도록 하십시오:{{ config(materialized='view') }} with actor_summary as ( SELECT id, any(actor_name) as name, uniqExact(movie_id) as num_movies, avg(rank) as avg_rank, uniqExact(genre) as genres, uniqExact(director_name) as directors, max(created_at) as updated_at FROM ( SELECT {{ source('imdb', 'actors') }}.id as id, concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name, {{ source('imdb', 'movies') }}.id as movie_id, {{ source('imdb', 'movies') }}.rank as rank, genre, concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name, created_at FROM {{ source('imdb', 'actors') }} JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id ) GROUP BY id ) select * from actor_summary최종 actor_summary에
updated_at컬럼을 포함했다는 점에 유의하십시오. 이는 이후 증분 머티리얼라이제이션에 사용됩니다. -
imdb디렉터리에서dbt run명령을 실행하세요.clickhouse-user@clickhouse:~/imdb$ dbt run 15:05:35 Running with dbt=1.1.0 15:05:35 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics 15:05:35 15:05:36 Concurrency: 1 threads (target='dev') 15:05:36 15:05:36 1 of 1 START view model imdb_dbt.actor_summary.................................. [RUN] 15:05:37 1 of 1 OK created view model imdb_dbt.actor_summary............................. [OK in 1.00s] 15:05:37 15:05:37 Finished running 1 view model in 1.97s. 15:05:37 15:05:37 Completed successfully 15:05:37 15:05:37 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1 -
dbt는 요청한 대로 model을 ClickHouse의 뷰로 생성합니다. 이제 이 뷰에 직접 쿼리할 수 있습니다. 이 뷰는
imdb_dbt데이터베이스에 생성되며, 이는clickhouse_imdbprofile 아래~/.dbt/profiles.yml파일의 스키마(schema) 매개변수로 결정됩니다.SHOW DATABASES;+------------------+ |name | +------------------+ |INFORMATION_SCHEMA| |default | |imdb | |imdb_dbt | <---dbt로 생성됨! |information_schema| |system | +------------------+이 뷰를 쿼리하면 더 간단한 구문으로 앞서 실행한 쿼리의 결과를 재현할 수 있습니다:
SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;+------+------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+------------+----------+------------------+------+---------+-------------------+ |45332 |Mel Blanc |832 |6.175853582979779 |18 |84 |2022-04-26 15:26:55| |621468|Bess Flowers|659 |5.57727638854796 |19 |293 |2022-04-26 15:26:57| |372839|Lee Phelps |527 |5.032976449684617 |18 |261 |2022-04-26 15:26:56| |283127|Tom London |525 |2.8721716524875673|17 |203 |2022-04-26 15:26:56| |356804|Bud Osborne |515 |2.0389507108727773|15 |149 |2022-04-26 15:26:56| +------+------------+----------+------------------+------+---------+-------------------+
테이블 머티리얼라이즈 생성하기
이전 예시에서 모델은 뷰로 구체화되었습니다. 일부 쿼리에는 이것만으로도 충분한 성능을 제공할 수 있지만, 더 복잡한 SELECT 또는 자주 실행되는 쿼리는 테이블로 구체화하는 편이 더 적합할 수 있습니다. 이러한 머티리얼라이즈는 BI 도구에서 조회할 모델에 유용하며, 더 빠른 사용 경험을 제공하는 데 도움이 됩니다. 이는 사실상 쿼리 결과를 새로운 테이블로 저장하므로, 그에 따른 스토리지 오버헤드가 발생합니다. 즉, INSERT TO SELECT가 실행됩니다. 이 테이블은 매번 다시 생성되며, 다시 말해 증분 방식이 아닙니다. 따라서 큰 결과 집합은 실행 시간이 길어질 수 있습니다. 자세한 내용은 dbt 제한 사항을 참조하십시오.
-
actors_summary.sql파일을 수정하여materialized매개변수를table로 설정합니다.ORDER BY가 어떻게 정의되어 있는지와MergeTree테이블 엔진을 사용한다는 점에 주목하십시오:{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='table') }} -
imdb디렉터리에서dbt run명령을 실행합니다. 이 작업은 완료까지 약간 더 오래 걸릴 수 있으며, 대부분의 환경에서 약 10초 정도 소요됩니다.clickhouse-user@clickhouse:~/imdb$ dbt run 15:13:27 Running with dbt=1.1.0 15:13:27 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics 15:13:27 15:13:28 Concurrency: 1 threads (target='dev') 15:13:28 15:13:28 1 of 1 START table model imdb_dbt.actor_summary................................. [RUN] 15:13:37 1 of 1 OK created table model imdb_dbt.actor_summary............................ [OK in 9.22s] 15:13:37 15:13:37 Finished running 1 table model in 10.20s. 15:13:37 15:13:37 Completed successfully 15:13:37 15:13:37 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1 -
imdb_dbt.actor_summary테이블이 생성되었는지 확인합니다:SHOW CREATE TABLE imdb_dbt.actor_summary;적절한 데이터 타입으로 정의된 테이블이 표시되어야 합니다:
+---------------------------------------- |statement +---------------------------------------- |CREATE TABLE imdb_dbt.actor_summary |( |`id` UInt32, |`first_name` String, |`last_name` String, |`num_movies` UInt64, |`updated_at` DateTime |) |ENGINE = MergeTree |ORDER BY (id, first_name, last_name) +---------------------------------------- -
이 테이블의 결과가 이전 응답과 일치하는지 확인합니다. 이제 모델이 테이블로 구체화되었으므로 응답 시간이 눈에 띄게 개선된 것을 확인할 수 있습니다:
SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;+------+------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+------------+----------+------------------+------+---------+-------------------+ |45332 |Mel Blanc |832 |6.175853582979779 |18 |84 |2022-04-26 15:26:55| |621468|Bess Flowers|659 |5.57727638854796 |19 |293 |2022-04-26 15:26:57| |372839|Lee Phelps |527 |5.032976449684617 |18 |261 |2022-04-26 15:26:56| |283127|Tom London |525 |2.8721716524875673|17 |203 |2022-04-26 15:26:56| |356804|Bud Osborne |515 |2.0389507108727773|15 |149 |2022-04-26 15:26:56| +------+------------+----------+------------------+------+---------+-------------------+이 모델에 대해 다른 쿼리도 자유롭게 실행해 보십시오. 예를 들어, 5편을 초과해 출연한 배우 중 평균 평점이 가장 높은 배우는 누구인지 확인할 수 있습니다.
SELECT * FROM imdb_dbt.actor_summary WHERE num_movies > 5 ORDER BY avg_rank DESC LIMIT 10;
증분 머티리얼라이즈 생성하기
이전 예시에서는 모델을 머티리얼라이즈하기 위한 테이블을 생성했습니다. 이 테이블은 dbt를 실행할 때마다 다시 생성됩니다. 결과 집합이 크거나 변환이 복잡한 경우, 이 방식은 현실적이지 않거나 비용이 매우 많이 들 수 있습니다. 이러한 문제를 해결하고 빌드 시간을 줄이기 위해 dbt는 증분 머티리얼라이즈를 제공합니다. 이를 사용하면 마지막 실행 이후 변경된 레코드를 테이블에 삽입하거나 업데이트할 수 있으므로 이벤트성 데이터에 적합합니다. 내부적으로는 먼저 업데이트된 모든 레코드가 포함된 임시 테이블을 만든 다음, 변경되지 않은 레코드와 업데이트된 레코드를 모두 새 대상 테이블(target table)에 삽입합니다. 따라서 큰 결과 집합에서는 table 모델과 유사한 제약 사항이 있습니다.
큰 집합에서 이러한 제약을 극복하기 위해 어댑터는 'inserts_only' 모드를 지원합니다. 이 모드에서는 임시 테이블을 만들지 않고 모든 업데이트를 대상 테이블에 삽입합니다(자세한 내용은 아래 참조).
이 예시를 설명하기 위해 배우 "Clicky McClickHouse"를 추가하겠습니다. 그는 무려 910편의 영화에 출연하며, Mel Blanc보다도 더 많은 영화에 출연한 인물이 됩니다.
-
먼저 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파일을 다음과 같이 수정하십시오:{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id') }} with actor_summary as ( SELECT id, any(actor_name) as name, uniqExact(movie_id) as num_movies, avg(rank) as avg_rank, uniqExact(genre) as genres, uniqExact(director_name) as directors, max(created_at) as updated_at FROM ( SELECT {{ source('imdb', 'actors') }}.id as id, concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name, {{ source('imdb', 'movies') }}.id as movie_id, {{ source('imdb', 'movies') }}.rank as rank, genre, concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name, created_at FROM {{ source('imdb', 'actors') }} JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id ) GROUP BY id ) select * from actor_summary {% if is_incremental() %} -- 이 필터는 증분 실행 시에만 적용됩니다 where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}}) {% endif %}이 모델은
roles및actors테이블의 업데이트와 추가에만 반응합니다. 모든 테이블에 반응하도록 하려면 이 모델을 여러 개의 하위 모델로 나누고, 각 하위 모델에 자체 증분 기준을 설정하는 것이 좋습니다. 이후 이러한 모델은 서로 참조하고 연결할 수 있습니다. 모델 간 교차 참조에 대한 자세한 내용은 here를 참조하십시오. - unique_key - 어댑터가 행을 고유하게 식별할 수 있도록 unique_key를 제공해야 합니다. 이 경우 쿼리의
-
dbt run을 실행하고 생성된 테이블의 결과를 확인합니다:clickhouse-user@clickhouse:~/imdb$ dbt run 15:33:34 Running with dbt=1.1.0 15:33:34 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics 15:33:34 15:33:35 Concurrency: 1 threads (target='dev') 15:33:35 15:33:35 1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN] 15:33:41 1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 6.33s] 15:33:41 15:33:41 Finished running 1 incremental model in 7.30s. 15:33:41 15:33:41 Completed successfully 15:33:41 15:33:41 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;+------+------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+------------+----------+------------------+------+---------+-------------------+ |45332 |Mel Blanc |832 |6.175853582979779 |18 |84 |2022-04-26 15:26:55| |621468|Bess Flowers|659 |5.57727638854796 |19 |293 |2022-04-26 15:26:57| |372839|Lee Phelps |527 |5.032976449684617 |18 |261 |2022-04-26 15:26:56| |283127|Tom London |525 |2.8721716524875673|17 |203 |2022-04-26 15:26:56| |356804|Bud Osborne |515 |2.0389507108727773|15 |149 |2022-04-26 15:26:56| +------+------------+----------+------------------+------+---------+-------------------+ -
이제 증분 업데이트를 보여주기 위해 모델에 데이터를 추가하겠습니다.
actors테이블에 배우 "Clicky McClickHouse"를 추가하세요:INSERT INTO imdb.actors VALUES (845466, 'Clicky', 'McClickHouse', 'M'); -
"Clicky"가 무작위로 선택된 영화 910편에 출연하게 해보겠습니다:
INSERT INTO imdb.roles SELECT now() as created_at, 845466 as actor_id, id as movie_id, 'Himself' as role FROM imdb.movies LIMIT 910 OFFSET 10000; -
기반이 되는 원본 테이블을 직접 쿼리해 dbt 모델을 거치지 않고, 이제 그가 실제로 가장 많이 출연한 배우인지 확인합니다:
SELECT id, any(actor_name) as name, uniqExact(movie_id) as num_movies, avg(rank) as avg_rank, uniqExact(genre) as unique_genres, uniqExact(director_name) as uniq_directors, max(created_at) as updated_at FROM ( SELECT imdb.actors.id as id, concat(imdb.actors.first_name, ' ', imdb.actors.last_name) as actor_name, imdb.movies.id as movie_id, imdb.movies.rank as rank, genre, concat(imdb.directors.first_name, ' ', imdb.directors.last_name) as director_name, created_at FROM imdb.actors JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id ) GROUP BY id ORDER BY num_movies DESC LIMIT 2;+------+-------------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+-------------------+----------+------------------+------+---------+-------------------+ |845466|Clicky McClickHouse|910 |1.4687938697032283|21 |662 |2022-04-26 16:20:36| |45332 |Mel Blanc |909 |5.7884792542982515|19 |148 |2022-04-26 16:17:42| +------+-------------------+----------+------------------+------+---------+-------------------+ -
dbt run을 실행한 뒤 모델이 업데이트되어 위의 결과와 일치하는지 확인하세요:clickhouse-user@clickhouse:~/imdb$ dbt run 16:12:16 Running with dbt=1.1.0 16:12:16 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics 16:12:16 16:12:17 Concurrency: 1 threads (target='dev') 16:12:17 16:12:17 1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN] 16:12:24 1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 6.82s] 16:12:24 16:12:24 Finished running 1 incremental model in 7.79s. 16:12:24 16:12:24 Completed successfully 16:12:24 16:12:24 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 2;+------+-------------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+-------------------+----------+------------------+------+---------+-------------------+ |845466|Clicky McClickHouse|910 |1.4687938697032283|21 |662 |2022-04-26 16:20:36| |45332 |Mel Blanc |909 |5.7884792542982515|19 |148 |2022-04-26 16:17:42| +------+-------------------+----------+------------------+------+---------+-------------------+
내부 동작
위와 같은 증분 업데이트를 위해 실행된 SQL 문은 ClickHouse의 쿼리 로그를 조회하면 확인할 수 있습니다.
SELECT event_time, query FROM system.query_log WHERE type='QueryStart' AND query LIKE '%dbt%'
AND event_time > subtractMinutes(now(), 15) ORDER BY event_time LIMIT 100;위 쿼리를 실행 기간에 맞게 조정하십시오. 결과 확인은 사용자가 직접 해야 하지만, 어댑터가 증분 업데이트를 수행할 때 사용하는 일반적인 전략은 다음과 같습니다.
- 어댑터는 임시 테이블
actor_sumary__dbt_tmp를 생성합니다. 변경된 행은 이 테이블로 스트리밍됩니다. - 새 테이블
actor_summary_new,를 생성합니다. 그런 다음 이전 테이블의 행을 이전 테이블에서 새 테이블로 스트리밍하면서, 행 ID가 임시 테이블에 존재하지 않는지 확인합니다. 이렇게 하면 업데이트와 중복을 효과적으로 처리할 수 있습니다. - 임시 테이블의 결과를 새
actor_summary테이블로 스트리밍합니다: - 마지막으로
EXCHANGE TABLES구문을 통해 새 테이블을 이전 버전과 원자적으로 교환합니다. 이후 이전 테이블과 임시 테이블을 삭제합니다.
이는 아래와 같이 시각화됩니다:

이 전략은 매우 큰 모델에서는 문제가 될 수 있습니다. 자세한 내용은 제한 사항을 참조하십시오.
Append Strategy (삽입 전용 모드)
증분 모델에서 대규모 데이터셋의 한계를 보완하기 위해 어댑터는 dbt 구성 매개변수 incremental_strategy를 사용합니다. 이 매개변수는 append 값으로 설정할 수 있습니다. 이렇게 설정하면 업데이트된 행이 대상 테이블(즉, imdb_dbt.actor_summary)에 직접 삽입되고, 임시 테이블은 생성되지 않습니다.
참고: Append only 모드를 사용하려면 데이터가 불변이어야 하거나 중복이 허용되어야 합니다. 변경된 행을 지원하는 증분 테이블 모델이 필요하다면 이 모드를 사용하지 마십시오.
이 모드를 설명하기 위해 새 배우를 한 명 더 추가한 다음, incremental_strategy='append'로 dbt run을 다시 실행하겠습니다.
-
actor_summary.sql에서 append only 모드를 구성합니다:
{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='append') }} -
유명한 배우를 한 명 더 추가합니다. Danny DeBito입니다.
INSERT INTO imdb.actors VALUES (845467, 'Danny', 'DeBito', 'M'); -
Danny를 무작위 영화 920편에 출연시킵니다.
INSERT INTO imdb.roles SELECT now() as created_at, 845467 as actor_id, id as movie_id, 'Himself' as role FROM imdb.movies LIMIT 920 OFFSET 10000; -
dbt run을 실행하고 actor-summary 테이블에 Danny가 추가되었는지 확인합니다.
clickhouse-user@clickhouse:~/imdb$ dbt run 16:12:16 Running with dbt=1.1.0 16:12:16 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 186 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics 16:12:16 16:12:17 Concurrency: 1 threads (target='dev') 16:12:17 16:12:17 1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN] 16:12:24 1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 0.17s] 16:12:24 16:12:24 Finished running 1 incremental model in 0.19s. 16:12:24 16:12:24 Completed successfully 16:12:24 16:12:24 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 3;+------+-------------------+----------+------------------+------+---------+-------------------+ |id |name |num_movies|avg_rank |genres|directors|updated_at | +------+-------------------+----------+------------------+------+---------+-------------------+ |845467|Danny DeBito |920 |1.4768987303293204|21 |670 |2022-04-26 16:22:06| |845466|Clicky McClickHouse|910 |1.4687938697032283|21 |662 |2022-04-26 16:20:36| |45332 |Mel Blanc |909 |5.7884792542982515|19 |148 |2022-04-26 16:17:42| +------+-------------------+----------+------------------+------+---------+-------------------+
이 증분 실행이 "Clicky"를 삽입했을 때보다 얼마나 더 빨랐는지 확인해 보십시오.
query_log 테이블을 다시 확인하면 두 번의 증분 실행 간 차이를 확인할 수 있습니다:
INSERT INTO imdb_dbt.actor_summary ("id", "name", "num_movies", "avg_rank", "genres", "directors", "updated_at")
WITH actor_summary AS (
SELECT id,
any(actor_name) AS name,
uniqExact(movie_id) AS num_movies,
avg(rank) AS avg_rank,
uniqExact(genre) AS genres,
uniqExact(director_name) AS directors,
max(created_at) AS updated_at
FROM (
SELECT imdb.actors.id AS id,
concat(imdb.actors.first_name, ' ', imdb.actors.last_name) AS actor_name,
imdb.movies.id AS movie_id,
imdb.movies.rank AS rank,
genre,
concat(imdb.directors.first_name, ' ', imdb.directors.last_name) AS director_name,
created_at
FROM imdb.actors
JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id
LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id
LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id
LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id
LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id
)
GROUP BY id
)
SELECT *
FROM actor_summary
-- 이 필터는 증분 실행 시에만 적용됩니다
WHERE id > (SELECT max(id) FROM imdb_dbt.actor_summary) OR updated_at > (SELECT max(updated_at) FROM imdb_dbt.actor_summary)이번 실행에서는 새 행만 imdb_dbt.actor_summary 테이블에 바로 추가되고, 테이블은 생성되지 않습니다.
삭제 및 삽입 모드(실험적)
ClickHouse는 그동안 비동기 뮤테이션 형태로만 업데이트와 삭제를 제한적으로 지원해 왔습니다. 이는 IO 사용량이 매우 클 수 있으므로 일반적으로 피하는 것이 좋습니다.
ClickHouse 22.8에서는 경량한 삭제가 도입되었고, ClickHouse 25.7에서는 경량 업데이트가 도입되었습니다. 이러한 기능이 도입되면서 비동기적으로 구체화되더라도 단일 업데이트 쿼리로 인한 변경 사항은 사용자 관점에서 즉시 반영됩니다.
이 모드는 모델에서 incremental_strategy 매개변수로 구성할 수 있습니다. 즉,
{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='delete+insert') }}이 전략은 대상 모델의 테이블에서 직접 수행되므로 작업 중 문제가 발생하면 증분 모델의 데이터가 유효하지 않은 상태가 될 가능성이 높습니다. atomic update가 없기 때문입니다.
요약하면, 이 접근 방식은 다음과 같습니다:
- 어댑터가 임시 테이블
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 작업이 성공적으로 완료될 때까지 원본 테이블을 수정하지 않으므로 다른 전략보다 더 안전합니다. 중간에 실패하더라도 원본 테이블은 수정되지 않습니다.
- 데이터 엔지니어링 모범 사례인 "파티션 불변성"을 구현합니다. 따라서 증분 및 병렬 데이터 처리, 롤백 등이 더 단순해집니다.

스냅샷 생성
dbt 스냅샷은 시간에 따라 변경되는 모델의 변경 이력을 기록할 수 있게 해줍니다. 이를 통해 모델에 대해 특정 시점 기준 쿼리를 수행할 수 있으며, 분석가는 모델의 이전 상태를 "과거 시점으로 되돌아가" 확인할 수 있습니다. 이는 행이 유효한 기간을 기록하는 시작일 및 종료일 컬럼을 사용하는 type-2 Slowly Changing Dimensions 방식으로 구현됩니다. 이 기능은 ClickHouse 어댑터에서 지원되며, 아래에서 예시를 보여줍니다.
이 예시는 Creating an Incremental Table Model을 완료한 상태라고 가정합니다. actor_summary.sql에서 inserts_only=True를 설정하지 마십시오. models/actor_summary.sql은 다음과 같아야 합니다:
{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id') }}
with actor_summary as (
SELECT id,
any(actor_name) as name,
uniqExact(movie_id) as num_movies,
avg(rank) as avg_rank,
uniqExact(genre) as genres,
uniqExact(director_name) as directors,
max(created_at) as updated_at
FROM (
SELECT {{ source('imdb', 'actors') }}.id as id,
concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name,
{{ source('imdb', 'movies') }}.id as movie_id,
{{ source('imdb', 'movies') }}.rank as rank,
genre,
concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name,
created_at
FROM {{ source('imdb', 'actors') }}
JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id
LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id
LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id
LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id
LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id
)
GROUP BY id
)
select *
from actor_summary
{% if is_incremental() %}
-- 이 필터는 증분 실행 시에만 적용됩니다
where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})
{% endif %}-
snapshots디렉터리에actor_summary파일을 생성합니다.touch snapshots/actor_summary.sql -
actor_summary.sql 파일의 내용을 다음과 같이 업데이트합니다.
{% snapshot actor_summary_snapshot %} {{ config( target_schema='snapshots', unique_key='id', strategy='timestamp', updated_at='updated_at', ) }} select * from {{ref('actor_summary')}} {% endsnapshot %}
이 내용과 관련해 몇 가지 참고할 사항이 있습니다.
- select 쿼리는 시간에 따라 스냅샷으로 저장할 결과를 정의합니다.
ref함수는 앞서 생성한 actor_summary 모델을 참조하는 데 사용됩니다. - 레코드 변경을 나타내려면
timestamp컬럼이 필요합니다. 여기서는 updated_at 컬럼(증분 테이블 모델 생성 참고)을 사용할 수 있습니다.strategy매개변수는 업데이트를 표시하는 데timestamp를 사용함을 의미하며,updated_at매개변수는 사용할 컬럼을 지정합니다. 모델에 이 컬럼이 없다면 대신 check strategy를 사용할 수도 있습니다. 이 방법은 훨씬 비효율적이며, 비교할 컬럼 목록을 사용자가 직접 지정해야 합니다. dbt는 이 컬럼들의 현재 값과 과거 값을 비교해 변경 사항을 기록합니다(값이 같으면 아무 작업도 수행하지 않음).
-
dbt snapshot명령을 실행합니다.clickhouse-user@clickhouse:~/imdb$ dbt snapshot 13:26:23 Running with dbt=1.1.0 13:26:23 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics 13:26:23 13:26:25 Concurrency: 1 threads (target='dev') 13:26:25 13:26:25 1 of 1 START snapshot snapshots.actor_summary_snapshot...................... [RUN] 13:26:25 1 of 1 OK snapshotted snapshots.actor_summary_snapshot...................... [OK in 0.79s] 13:26:25 13:26:25 Finished running 1 snapshot in 2.11s. 13:26:25 13:26:25 Completed successfully 13:26:25 13:26:25 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
actor_summary_snapshot 테이블이 snapshots DB에 생성된 것을 확인할 수 있습니다. 이는 target_schema 매개변수로 결정됩니다.
-
이 데이터를 샘플링해 보면 dbt가 dbt_valid_from 및 dbt_valid_to 컬럼을 포함했음을 확인할 수 있습니다. 후자의 값은 NULL로 설정되어 있습니다. 이후 실행에서 이 값이 업데이트됩니다.
SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;+------+----------+------------+----------+-------------------+------------+ |id |first_name|last_name |num_movies|dbt_valid_from |dbt_valid_to| +------+----------+------------+----------+-------------------+------------+ |845467|Danny |DeBito |920 |2022-05-25 19:33:32|NULL | |845466|Clicky |McClickHouse|910 |2022-05-25 19:32:34|NULL | |45332 |Mel |Blanc |909 |2022-05-25 19:31:47|NULL | |621468|Bess |Flowers |672 |2022-05-25 19:31:47|NULL | |283127|Tom |London |549 |2022-05-25 19:31:47|NULL | +------+----------+------------+----------+-------------------+------------+ -
가장 좋아하는 배우 Clicky McClickHouse가 영화 10편에 더 출연하도록 하세요.
INSERT INTO imdb.roles SELECT now() as created_at, 845466 as actor_id, rand(number) % 412320 as movie_id, 'Himself' as role FROM system.numbers LIMIT 10; -
imdb디렉터리에서dbt run명령을 다시 실행하세요. 그러면 증분 모델이 업데이트됩니다. 이 작업이 완료되면 변경 사항을 기록하기 위해dbt snapshot을 실행하세요.clickhouse-user@clickhouse:~/imdb$ dbt run 13:46:14 Running with dbt=1.1.0 13:46:14 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics 13:46:14 13:46:15 Concurrency: 1 threads (target='dev') 13:46:15 13:46:15 1 of 1 START incremental model imdb_dbt.actor_summary....................... [RUN] 13:46:18 1 of 1 OK created incremental model imdb_dbt.actor_summary.................. [OK in 2.76s] 13:46:18 13:46:18 Finished running 1 incremental model in 3.73s. 13:46:18 13:46:18 Completed successfully 13:46:18 13:46:18 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1 clickhouse-user@clickhouse:~/imdb$ dbt snapshot 13:46:26 Running with dbt=1.1.0 13:46:26 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics 13:46:26 13:46:27 Concurrency: 1 threads (target='dev') 13:46:27 13:46:27 1 of 1 START snapshot snapshots.actor_summary_snapshot...................... [RUN] 13:46:31 1 of 1 OK snapshotted snapshots.actor_summary_snapshot...................... [OK in 4.05s] 13:46:31 13:46:31 Finished running 1 snapshot in 5.02s. 13:46:31 13:46:31 Completed successfully 13:46:31 13:46:31 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1 -
이제 스냅샷을 쿼리하면 Clicky McClickHouse에 대한 행이 2개 있는 것을 확인할 수 있습니다. 이전 항목에는 이제 dbt_valid_to 값이 설정되어 있습니다. 새 값은 dbt_valid_from 컬럼에 동일한 값으로 기록되고, dbt_valid_to 값은 null입니다. 새 행이 있었다면 이 역시 스냅샷에 추가되었을 것입니다.
SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;+------+----------+------------+----------+-------------------+-------------------+ |id |first_name|last_name |num_movies|dbt_valid_from |dbt_valid_to | +------+----------+------------+----------+-------------------+-------------------+ |845467|Danny |DeBito |920 |2022-05-25 19:33:32|NULL | |845466|Clicky |McClickHouse|920 |2022-05-25 19:34:37|NULL | |845466|Clicky |McClickHouse|910 |2022-05-25 19:32:34|2022-05-25 19:34:37| |45332 |Mel |Blanc |909 |2022-05-25 19:31:47|NULL | |621468|Bess |Flowers |672 |2022-05-25 19:31:47|NULL | +------+----------+------------+----------+-------------------+-------------------+
dbt 스냅샷에 대한 자세한 내용은 여기를 참조하십시오.
seed 사용하기
dbt는 CSV 파일에서 데이터를 로드하는 기능을 제공합니다. 이 기능은 데이터베이스의 대규모 내보내기 데이터를 로드하는 데는 적합하지 않으며, 일반적으로 코드 테이블과 dictionaries에 사용하는 작은 파일에 더 적합합니다. 예를 들어 국가 코드를 국가 이름에 매핑할 때 사용할 수 있습니다. 간단한 예시로, seed 기능을 사용해 장르 코드 목록을 생성한 다음 업로드해 보겠습니다.
-
기존 데이터셋에서 장르 코드 목록을 생성합니다. dbt 디렉터리에서
clickhouse-client를 사용해seeds/genre_codes.csv파일을 만드십시오.clickhouse-user@clickhouse:~/imdb$ clickhouse-client --password <password> --query "SELECT genre, ucase(substring(genre, 1, 3)) as code FROM imdb.genres GROUP BY genre LIMIT 100 FORMAT CSVWithNames" > seeds/genre_codes.csv -
dbt seed명령을 실행합니다. 그러면 데이터베이스imdb_dbt에 새 테이블genre_codes가 생성되고(이는 schema 구성에 정의되어 있음), CSV 파일의 행이 이 테이블에 로드됩니다.clickhouse-user@clickhouse:~/imdb$ dbt seed 17:03:23 Running with dbt=1.1.0 17:03:23 Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 1 seed file, 6 sources, 0 exposures, 0 metrics 17:03:23 17:03:24 Concurrency: 1 threads (target='dev') 17:03:24 17:03:24 1 of 1 START seed file imdb_dbt.genre_codes..................................... [RUN] 17:03:24 1 of 1 OK loaded seed file imdb_dbt.genre_codes................................. [INSERT 21 in 0.65s] 17:03:24 17:03:24 Finished running 1 seed in 1.62s. 17:03:24 17:03:24 Completed successfully 17:03:24 17:03:24 Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1 -
데이터가 로드되었는지 확인합니다:
SELECT * FROM imdb_dbt.genre_codes LIMIT 10;+-------+----+ |genre |code| +-------+----+ |Drama |DRA | |Romance|ROM | |Short |SHO | |Mystery|MYS | |Adult |ADU | |Family |FAM | |Action |ACT | |Sci-Fi |SCI | |Horror |HOR | |War |WAR | +-------+----+=
추가 정보
이전 가이드에서는 dbt 기능의 일부만 간략히 소개했습니다. 자세한 내용은 우수한 dbt 문서를 참조하십시오.