Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Guias

Suportado pelo ClickHouse

Esta seção reúne guias para configurar o dbt e o adaptador do ClickHouse, além de um exemplo de uso do dbt com o ClickHouse usando um conjunto de dados público do IMDB. O exemplo abrange as seguintes etapas:

  1. Criar um projeto dbt e configurar o adaptador do ClickHouse.
  2. Definir um modelo.
  3. Atualizar um modelo.
  4. Criar um modelo incremental.
  5. Criar um modelo de snapshot.
  6. Usar VIEWs materializadas.

Esses guias foram elaborados para serem usados em conjunto com o restante da documentação, os recursos e configurações e a referência de materializações.

Configuração

Siga as instruções na seção Configuração do dbt e do adaptador ClickHouse para preparar seu ambiente.

Importante: o conteúdo a seguir foi testado com Python 3.9.

Prepare o ClickHouse

O dbt se destaca na modelagem de dados altamente relacionais. Para fins de exemplo, fornecemos um pequeno conjunto de dados do IMDB com o seguinte esquema relacional. Esse conjunto de dados vem do repositório de conjuntos de dados relacionais. Ele é simples em comparação com os esquemas normalmente usados com dbt, mas representa uma amostra gerenciável:

Esquema de tabelas do IMDB

Usamos um subconjunto dessas tabelas, como mostrado.

Crie as tabelas a seguir:

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);

Usamos a função s3 para ler os dados de origem a partir de endpoints públicos e inserir os dados. Execute os comandos a seguir para preencher as tabelas:

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');

A execução dessas etapas pode variar dependendo da sua largura de banda, mas cada uma deve levar apenas alguns segundos para ser concluída. Execute a consulta a seguir para gerar um resumo de cada ator, em ordem pelo maior número de aparições em filmes, e confirmar que os dados foram carregados com sucesso:

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;

A resposta deve ser assim:

+------+------------+----------+------------------+-------------+--------------+-------------------+
|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|
+------+------------+----------+------------------+-------------+--------------+-------------------+

Nos guias posteriores, converteremos esta consulta em um modelo - materializando-o no ClickHouse como uma view e uma tabela no dbt.

Conectando ao ClickHouse

  1. Crie um projeto dbt. Neste caso, damos a ele o nome da nossa source imdb. Quando solicitado, selecione clickhouse como banco de dados de origem.

    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
  2. Entre na pasta do seu projeto com cd:

    cd imdb
  3. Neste ponto, você precisará de um editor de texto de sua preferência. Nos exemplos abaixo, usamos o popular VS Code. Ao abrir o diretório IMDB, você deverá ver uma coleção de arquivos yml e sql:

    Novo projeto dbt
  4. Atualize o arquivo dbt_project.yml para especificar nosso primeiro modelo, actor_summary, e defina o profile como clickhouse_imdb.

    profile do dbt
    profile do dbt
  5. Em seguida, precisamos fornecer ao dbt os detalhes de conexão da nossa instância do ClickHouse. Adicione o seguinte ao arquivo ~/.dbt/profiles.yml.

    clickhouse_imdb:
      target: dev
      outputs:
        dev:
          type: clickhouse
          schema: imdb_dbt
          host: localhost
          port: 8123
          user: default
          password: ''
          secure: False

    Observe que será necessário alterar o usuário e a senha. Há outras configurações disponíveis documentadas aqui.

  6. No diretório IMDB, execute o comando dbt debug para confirmar se o dbt consegue se conectar ao 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!

    Confirme que a resposta inclui Connection test: [OK connection ok], indicando que a conexão foi bem-sucedida.

Criando uma materialização de view simples

Ao usar a materialização de view, um modelo é recriado como uma view a cada execução, por meio de uma instrução CREATE VIEW AS no ClickHouse. Isso não requer armazenamento adicional de dados, mas as consultas serão mais lentas do que com materializações de tabela.

  1. No diretório imdb, exclua o diretório models/example:

    clickhouse-user@clickhouse:~/imdb$ rm -rf models/example
  2. Crie um novo arquivo em actors, dentro da pasta models. Aqui, criamos arquivos, cada um representando um modelo de ator:

    clickhouse-user@clickhouse:~/imdb$ mkdir models/actors
  3. Crie os arquivos schema.yml e actor_summary.sql na pasta models/actors.

    clickhouse-user@clickhouse:~/imdb$ touch models/actors/actor_summary.sql
    clickhouse-user@clickhouse:~/imdb$ touch models/actors/schema.yml

    O arquivo schema.yml define nossas tabelas. Depois, elas estarão disponíveis para uso em macros. Edite models/actors/schema.yml para que contenha este conteúdo:

    version: 2
    
    sources:
    - name: imdb
      tables:
      - name: directors
      - name: actors
      - name: roles
      - name: movies
      - name: genres
      - name: movie_directors

    O actors_summary.sql define o modelo propriamente dito. Observe que, na função config, também solicitamos que o modelo seja materializado como uma view no ClickHouse. Nossas tabelas são referenciadas no arquivo schema.yml por meio da função source; por exemplo, source('imdb', 'movies') refere-se à tabela movies no banco de dados imdb. Edite models/actors/actors_summary.sql para que contenha este conteúdo:

    {{ 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

    Observe que incluímos a coluna updated_at no nosso actor_summary final. Usamos isso mais tarde em materializações incrementais.

  4. No diretório imdb, execute o comando 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
  5. O dbt representará o model como uma view no ClickHouse, conforme solicitado. Agora podemos consultar essa view diretamente. Essa view terá sido criada no banco de dados imdb_dbt — isso é determinado pelo parâmetro schema no arquivo ~/.dbt/profiles.yml, no perfil clickhouse_imdb.

    SHOW DATABASES;
    +------------------+
    |name              |
    +------------------+
    |INFORMATION_SCHEMA|
    |default           |
    |imdb              |
    |imdb_dbt          |  <---criado pelo dbt!
    |information_schema|
    |system            |
    +------------------+

    Ao consultar esta view, podemos reproduzir os resultados da nossa consulta anterior com uma sintaxe mais simples:

    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|
    +------+------------+----------+------------------+------+---------+-------------------+

Criando uma materialização como tabela

No exemplo anterior, nosso modelo foi materializado como uma view. Embora isso possa oferecer desempenho suficiente para algumas consultas, instruções SELECT mais complexas ou consultas executadas com frequência podem ter melhor desempenho quando materializadas como tabela. Essa materialização é útil para modelos que serão consultados por ferramentas de BI, garantindo uma experiência mais rápida para os usuários. Na prática, isso faz com que os resultados da consulta sejam armazenados em uma nova tabela, com a sobrecarga de armazenamento correspondente — ou seja, um INSERT TO SELECT é executado. Observe que essa tabela será reconstruída todas as vezes, ou seja, não é incremental. Portanto, grandes conjuntos de resultados podem levar a tempos de execução longos — consulte Limitações do dbt.

  1. Modifique o arquivo actors_summary.sql para que o parâmetro materialized seja definido como table. Observe como ORDER BY é definido e note que usamos o mecanismo de tabela MergeTree:

    {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='table') }}
  2. No diretório imdb, execute o comando dbt run. Essa execução pode levar um pouco mais de tempo — cerca de 10s na maioria das máquinas.

    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
  3. Confirme a criação da tabela imdb_dbt.actor_summary:

    SHOW CREATE TABLE imdb_dbt.actor_summary;

    Você deverá ver a tabela com os tipos de dados apropriados:

    +----------------------------------------
    |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)
    +----------------------------------------
  4. Confirme que os resultados desta tabela são consistentes com as respostas anteriores. Observe a melhora perceptível no tempo de resposta agora que o modelo é uma tabela:

    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|
    +------+------------+----------+------------------+------+---------+-------------------+

    Sinta-se à vontade para executar outras consultas nesse modelo. Por exemplo, quais atores têm os filmes com melhor classificação entre aqueles com mais de 5 aparições?

    SELECT * FROM imdb_dbt.actor_summary WHERE num_movies > 5 ORDER BY avg_rank  DESC LIMIT 10;

Criando uma materialização incremental

O exemplo anterior criou uma tabela para materializar o modelo. Essa tabela será reconstruída a cada execução do dbt. Isso pode ser inviável e extremamente custoso para grandes conjuntos de resultados ou transformações complexas. Para enfrentar esse desafio e reduzir o tempo de compilação, o dbt oferece materializações incrementais. Isso permite que o dbt insira ou atualize registros em uma tabela desde a última execução, tornando essa abordagem apropriada para dados no estilo de eventos. Nos bastidores, uma tabela temporária é criada com todos os registros atualizados e, em seguida, todos os registros inalterados, bem como os registros atualizados, são inseridos em uma nova tabela de destino. Isso resulta em limitações semelhantes para grandes conjuntos de resultados, assim como no modelo de tabela.

Para contornar essas limitações em grandes conjuntos, o adaptador oferece o modo 'inserts_only', no qual todas as atualizações são inseridas na tabela de destino sem criar uma tabela temporária (mais sobre isso abaixo).

Para ilustrar este exemplo, adicionaremos o ator "Clicky McClickHouse", que aparecerá em incríveis 910 filmes, garantindo que ele tenha aparecido em mais filmes até mesmo do que Mel Blanc.

  1. Primeiro, modificamos nosso model para que ele seja do tipo incremental. Essa alteração exige:

    1. unique_key - Para garantir que o adaptador consiga identificar as linhas de forma única, precisamos fornecer uma unique_key — neste caso, o campo id da nossa consulta será suficiente. Isso garante que não teremos linhas duplicadas na nossa tabela materializada. Para mais detalhes sobre restrições de unicidade, veja aqui.
    2. Filtro incremental - Também precisamos informar ao dbt como ele deve identificar quais linhas foram alteradas em uma execução incremental. Isso é feito fornecendo uma expressão delta. Normalmente, isso envolve um timestamp para dados de evento; por isso, usamos nosso campo de timestamp updated_at. Essa coluna, que por padrão recebe o valor de now() quando as linhas são inseridas, permite identificar novos registros. Além disso, precisamos identificar o caso alternativo em que novos atores são adicionados. Usando a variável {{this}} para representar a tabela materializada existente, chegamos à expressão where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}}). Incorporamos isso dentro da condição {% if is_incremental() %}, garantindo que ela seja usada apenas em execuções incrementais, e não quando a tabela é criada pela primeira vez. Para mais detalhes sobre a filtragem de linhas em modelos incrementais, veja esta discussão na documentação do dbt.

    Atualize o arquivo actor_summary.sql da seguinte forma:

    {{ 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() %}
    
    -- este filtro será aplicado apenas em uma execução incremental
    where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})
    
    {% endif %}

    Observe que nosso model responderá apenas a atualizações e adições nas tabelas roles e actors. Para responder a todas as tabelas, recomenda-se dividir este model em vários submodels, cada um com seus próprios critérios incrementais. Esses models, por sua vez, podem ser referenciados e conectados. Para mais detalhes sobre referências cruzadas entre models, veja aqui.

  2. Execute um dbt run e confirme os resultados na tabela resultante:

    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=1
    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|
    +------+------------+----------+------------------+------+---------+-------------------+
  3. Agora vamos adicionar dados ao nosso modelo para ilustrar uma atualização incremental. Adicione nosso ator "Clicky McClickHouse" à tabela actors:

    INSERT INTO imdb.actors VALUES (845466, 'Clicky', 'McClickHouse', 'M');
  4. Vamos fazer com que "Clicky" estrele em 910 filmes aleatórios:

    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;
  5. Confirme que ele agora é, de fato, o ator com mais aparições consultando diretamente a tabela de origem subjacente, sem passar por nenhum modelo do 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|
    +------+-------------------+----------+------------------+------+---------+-------------------+
  6. Execute um dbt run e confirme que nosso modelo foi atualizado e corresponde aos resultados acima:

    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=1
    SELECT * 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|
    +------+-------------------+----------+------------------+------+---------+-------------------+

Aspectos internos

Podemos identificar as instruções executadas para realizar a atualização incremental acima consultando o log de consultas do 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;

Ajuste a consulta acima ao período de execução. Deixamos a inspeção do resultado a cargo do usuário, mas destacamos a estratégia geral usada pelo adaptador para realizar atualizações incrementais:

  1. O adaptador cria uma tabela temporária actor_sumary__dbt_tmp. As linhas alteradas são enviadas para essa tabela.
  2. Uma nova tabela, actor_summary_new, é criada. As linhas da tabela antiga, por sua vez, são enviadas da tabela antiga para a nova, com uma verificação para garantir que os IDs das linhas não existam na tabela temporária. Isso lida de forma eficaz com atualizações e duplicatas.
  3. Os resultados da tabela temporária são enviados para a nova tabela actor_summary:
  4. Por fim, a nova tabela é trocada atomicamente com a versão antiga por meio de uma instrução EXCHANGE TABLES. A tabela antiga e a temporária são então removidas.

Isso é ilustrado abaixo:

atualizações incrementais no dbt

Essa estratégia pode apresentar desafios em modelos muito grandes. Para mais detalhes, consulte Limitações.

Estratégia Append (modo apenas inserções)

Para contornar as limitações de grandes conjuntos de dados em modelos incrementais, o adaptador usa o parâmetro de configuração do dbt incremental_strategy. Ele pode ser definido com o valor append. Quando isso é feito, as linhas atualizadas são inseridas diretamente na tabela de destino (também chamada de imdb_dbt.actor_summary) e nenhuma tabela temporária é criada. Observação: o modo append-only exige que seus dados sejam imutáveis ou que duplicatas sejam aceitáveis. Se você quiser um modelo de tabela incremental com suporte a linhas alteradas, não use este modo!

Para ilustrar este modo, vamos adicionar mais um ator novo e executar novamente o dbt run com incremental_strategy='append'.

  1. Configure o modo append-only em actor_summary.sql:

    {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='append') }}
  2. Vamos adicionar mais um ator famoso: Danny DeBito

    INSERT INTO imdb.actors VALUES (845467, 'Danny', 'DeBito', 'M');
  3. Vamos colocar Danny no elenco de 920 filmes aleatórios.

    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;
  4. Execute um dbt run e confirme que Danny foi adicionado à tabela actor_summary

    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=1
    SELECT * 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|
    +------+-------------------+----------+------------------+------+---------+-------------------+

Observe como essa execução incremental foi muito mais rápida do que a inserção de "Clicky".

Ao verificar novamente a tabela query_log, vemos as diferenças entre as 2 execuções incrementais:

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
-- este filtro só será aplicado em uma execução incremental
WHERE id > (SELECT max(id) FROM imdb_dbt.actor_summary) OR updated_at > (SELECT max(updated_at) FROM imdb_dbt.actor_summary)

Nesta execução, apenas as novas linhas são adicionadas diretamente à tabela imdb_dbt.actor_summary, sem envolver a criação de tabela.

Modo de exclusão e inserção (experimental)

Historicamente, o ClickHouse oferecia apenas suporte limitado a atualizações e exclusões, na forma de mutações assíncronas. Elas podem exigir uso de E/S extremamente intensivo e, em geral, devem ser evitadas.

O ClickHouse 22.8 introduziu as exclusões leves, e o ClickHouse 25.7 introduziu as atualizações leves. Com a introdução dessas funcionalidades, as alterações feitas por consultas de atualização individuais, mesmo quando materializadas de forma assíncrona, serão refletidas instantaneamente para o usuário.

Esse modo pode ser configurado para um modelo por meio do parâmetro incremental_strategy, ou seja.

{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='delete+insert') }}

Essa estratégia opera diretamente na tabela do modelo de destino, portanto, se houver algum problema durante a operação, os dados no modelo incremental provavelmente ficarão em um estado inválido — não há atualização atômica.

Em resumo, esta abordagem:

  1. O adaptador cria uma tabela temporária actor_sumary__dbt_tmp. As linhas alteradas são gravadas nessa tabela.
  2. Um DELETE é executado na tabela actor_summary atual. As linhas são excluídas por id com base em actor_sumary__dbt_tmp
  3. As linhas de actor_sumary__dbt_tmp são inseridas em actor_summary usando INSERT INTO actor_summary SELECT * FROM actor_sumary__dbt_tmp.

Esse processo é mostrado abaixo:

incremental com exclusão leve

modo insert_overwrite (experimental)

Executa as seguintes etapas:

  1. Crie uma tabela de staging (temporária) com a mesma estrutura da relação do modelo incremental: CREATE TABLE {staging} AS {target}.
  2. Insira apenas os novos registros (produzidos por SELECT) na tabela de staging.
  3. Substitua apenas as novas partições (presentes na tabela de staging) na tabela de destino.

Essa abordagem tem as seguintes vantagens:

  • É mais rápida do que a estratégia padrão porque não copia a tabela inteira.
  • É mais segura do que outras estratégias porque não modifica a tabela original até que a operação INSERT seja concluída com sucesso: em caso de falha intermediária, a tabela original não é modificada.
  • Implementa a prática recomendada de engenharia de dados de "imutabilidade das partições", o que simplifica o processamento de dados incremental e paralelo, rollbacks etc.
insert overwrite incremental

Criando um snapshot

Os snapshots do dbt permitem registrar, ao longo do tempo, as alterações em um modelo mutável. Isso, por sua vez, permite consultas em um ponto específico no tempo sobre os modelos, em que analistas podem "voltar no tempo" para ver o estado anterior de um modelo. Isso é feito usando dimensões de mudança lenta do tipo 2, nas quais colunas de data inicial e final registram quando uma linha era válida. Essa funcionalidade é compatível com o adaptador do ClickHouse e é demonstrada abaixo.

Este exemplo pressupõe que você concluiu Criando um modelo de tabela incremental. Certifique-se de que seu actor_summary.sql não defina inserts_only=True. Seu models/actor_summary.sql deve ficar assim:

   {{ 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() %}

   -- este filtro só será aplicado em uma execução incremental
   where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})

   {% endif %}
  1. Crie um arquivo actor_summary no diretório snapshots.

     touch snapshots/actor_summary.sql
  2. Atualize o conteúdo do arquivo actor_summary.sql com o conteúdo a seguir:

    {% snapshot actor_summary_snapshot %}
    
    {{
    config(
    target_schema='snapshots',
    unique_key='id',
    strategy='timestamp',
    updated_at='updated_at',
    )
    }}
    
    select * from {{ref('actor_summary')}}
    
    {% endsnapshot %}

Algumas observações sobre esse conteúdo:

  • A consulta select define os resultados que você deseja capturar em snapshots ao longo do tempo. A função ref é usada para referenciar o modelo actor_summary que criamos anteriormente.
  • Precisamos de uma coluna de timestamp para indicar alterações nos registros. Nossa coluna updated_at (consulte Criando um modelo de tabela incremental) pode ser usada aqui. O parâmetro strategy indica que usamos um timestamp para marcar atualizações, e o parâmetro updated_at especifica qual coluna usar. Se ele não estiver presente no seu modelo, você também pode usar a estratégia check. Isso é significativamente menos eficiente e exige que o usuário especifique uma lista de colunas para comparação. O dbt compara os valores atuais e históricos dessas colunas, registrando quaisquer alterações (ou não fazendo nada se forem idênticos).
  1. Execute o comando 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

Observe que foi criada uma tabela actor_summary_snapshot no banco de dados snapshots (definido pelo parâmetro target_schema).

  1. Ao examinar uma amostra desses dados, você verá como o dbt incluiu as colunas dbt_valid_from e dbt_valid_to. Esta última tem valores definidos como NULL. Nas execuções seguintes, isso será atualizado.

    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        |
    +------+----------+------------+----------+-------------------+------------+
  2. Faça nosso ator favorito, Clicky McClickHouse, aparecer em outros 10 filmes.

    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;
  3. Execute novamente o comando dbt run a partir do diretório imdb. Isso atualizará o modelo incremental. Quando isso for concluído, execute o dbt snapshot para capturar as alterações.

    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
  4. Se agora consultarmos nosso snapshot, observe que temos 2 linhas para Clicky McClickHouse. Nossa entrada anterior agora tem um valor em dbt_valid_to. Nosso novo valor é registrado com o mesmo valor na coluna dbt_valid_from e com dbt_valid_to igual a null. Se tivéssemos novas linhas, elas também seriam adicionadas ao snapshot.

    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               |
    +------+----------+------------+----------+-------------------+-------------------+

Para mais detalhes sobre os snapshots do dbt, veja aqui.

Usando seeds

O dbt permite carregar dados de arquivos CSV. Esse recurso não é adequado para carregar grandes exportações de um banco de dados; ele foi projetado mais para arquivos pequenos, normalmente usados para tabelas de códigos e dicionários, por exemplo, para mapear códigos de países para nomes de países. Neste exemplo simples, geramos e depois carregamos uma lista de códigos de gênero usando a funcionalidade de seed.

  1. Geramos uma lista de códigos de gênero a partir do nosso conjunto de dados existente. No diretório do dbt, use o clickhouse-client para criar um arquivo 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
  2. Execute o comando dbt seed. Isso criará uma nova tabela genre_codes no nosso banco de dados imdb_dbt (conforme definido na nossa configuração de schema) com as linhas do nosso arquivo 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
  3. Confirme que os dados foram carregados:

    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 |
    +-------+----+=

Mais informações

Os guias anteriores apenas mostram uma pequena parte das funcionalidades do dbt. Recomenda-se que os usuários leiam a excelente documentação do dbt.

Navigation