> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Guias para usar o dbt com ClickHouse

# Guias

export const ClickHouseSupportedBadge = () => {
  return <div className="ClickHouseSupportedBadge">
            <div className="ClickHouseSupportedIcon">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1.30762 1.39073C1.30762 1.3103 1.37465 1.22986 1.46849 1.22986H2.64824C2.72868 1.22986 2.80912 1.29689 2.80912 1.39073V14.4886C2.80912 14.5691 2.74209 14.6495 2.64824 14.6495H1.46849C1.38805 14.6495 1.30762 14.5825 1.30762 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M4.2832 1.39073C4.2832 1.3103 4.35023 1.22986 4.44408 1.22986H5.62383C5.70427 1.22986 5.7847 1.29689 5.7847 1.39073V14.4886C5.7847 14.5691 5.71767 14.6495 5.62383 14.6495H4.44408C4.36364 14.6495 4.2832 14.5825 4.2832 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M7.25977 1.39073C7.25977 1.3103 7.3268 1.22986 7.42064 1.22986H8.60039C8.68083 1.22986 8.76127 1.29689 8.76127 1.39073V14.4886C8.76127 14.5691 8.69423 14.6495 8.60039 14.6495H7.42064C7.3402 14.6495 7.25977 14.5825 7.25977 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M10.2354 1.39073C10.2354 1.3103 10.3024 1.22986 10.3962 1.22986H11.576C11.6564 1.22986 11.7369 1.29689 11.7369 1.39073V14.4886C11.7369 14.5691 11.6698 14.6495 11.576 14.6495H10.3962C10.3158 14.6495 10.2354 14.5825 10.2354 14.4886V1.39073Z" fill="currentColor" />
                    <path d="M13.2256 6.6057C13.2256 6.52526 13.2926 6.44482 13.3865 6.44482H14.5662C14.6466 6.44482 14.7271 6.51186 14.7271 6.6057V9.27354C14.7271 9.35398 14.6601 9.43442 14.5662 9.43442H13.3865C13.306 9.43442 13.2256 9.36739 13.2256 9.27354V6.6057Z" fill="currentColor" />
                </svg>
            </div>
            Suportado pelo ClickHouse
        </div>;
};

export const Image = ({img, alt, size = "lg"}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} />
      </Frame>
    </div>;
};

<ClickHouseSupportedBadge />

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 visões materializadas.

Esses guias foram elaborados para serem usados em conjunto com o restante da [documentação](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/index), os [recursos e configurações](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/features-and-configurations) e a [referência de materializações](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/materializations).

<div id="setup">
  ## Configuração
</div>

Siga as instruções na seção [Configuração do dbt e do adaptador ClickHouse](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/index) para preparar seu ambiente.

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

<div id="prepare-clickhouse">
  ### Prepare o ClickHouse
</div>

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](https://relational.fit.cvut.cz/dataset/IMDb). Ele é simples em comparação com os esquemas normalmente usados com dbt, mas representa uma amostra gerenciável:

<Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_01.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=966119520059d8223dac8c84e5908794" size="lg" alt="Esquema de tabelas do IMDB" width="2623" height="921" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_01.webp" />

Usamos um subconjunto dessas tabelas, como mostrado.

Crie as tabelas a seguir:

```sql theme={null}
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);
```

<Note>
  A coluna `created_at` da tabela `roles`, que tem `now()` como valor padrão. Vamos usá-la mais tarde para identificar atualizações incrementais nos nossos modelos — consulte [Modelos Incrementais](#creating-an-incremental-materialization).
</Note>

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:

```sql theme={null}
INSERT INTO imdb.actors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_actors.tsv.gz',
'TSVWithNames');

INSERT INTO imdb.directors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_directors.tsv.gz',
'TSVWithNames');

INSERT INTO imdb.genres
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies_genres.tsv.gz',
'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',
        'TSVWithNames');

INSERT INTO imdb.movies
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies.tsv.gz',
'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',
'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:

```sql theme={null}
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:

```response theme={null}
+------+------------+----------+------------------+-------------+--------------+-------------------+
|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.

<div id="connecting-to-clickhouse">
  ## Conectando ao ClickHouse
</div>

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.

   ```bash theme={null}
   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`:

   ```bash theme={null}
   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:

   <Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_02.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=1e758dcd7fabd633f1250792a0d866ed" size="lg" alt="Novo projeto dbt" width="1113" height="1087" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_02.webp" />

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

   <Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_03.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=7ab628f8cf11f9d6c526b0f0f1457d0a" size="lg" alt="profile do dbt" width="512" height="28" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_03.webp" />

   <Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_04.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=7c3d8306cc50c94bb253dbc8a316870d" size="lg" alt="profile do dbt" width="512" height="74" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_04.webp" />

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`.

   ```yml theme={null}
   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](https://github.com/silentsokolov/dbt-clickhouse#example-profile).

6. No diretório IMDB, execute o comando `dbt debug` para confirmar se o dbt consegue se conectar ao ClickHouse.

   ```bash theme={null}
   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.

<div id="creating-a-simple-view-materialization">
  ## Criando uma materialização de view simples
</div>

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`:

   ```bash theme={null}
   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:

   ```bash theme={null}
   clickhouse-user@clickhouse:~/imdb$ mkdir models/actors
   ```

3. Crie os arquivos `schema.yml` e `actor_summary.sql` na pasta `models/actors`.

   ```bash theme={null}
   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:

   ```yml theme={null}
   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:

   ```sql theme={null}
   {{ 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`.

   ```bash theme={null}
   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`.

   ```sql theme={null}
   SHOW DATABASES;
   ```

   ```response theme={null}
   +------------------+
   |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:

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
   ```

   ```response theme={null}
   +------+------------+----------+------------------+------+---------+-------------------+
   |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|
   +------+------------+----------+------------------+------+---------+-------------------+
   ```

<div id="creating-a-table-materialization">
  ## Criando uma materialização como tabela
</div>

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](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/index#limitations).

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`:

   ```sql theme={null}
   {{ 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.

   ```bash theme={null}
   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`:

   ```sql theme={null}
   SHOW CREATE TABLE imdb_dbt.actor_summary;
   ```

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

   ```response theme={null}
   +----------------------------------------
   |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:

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
   ```

   ```response theme={null}
   +------+------------+----------+------------------+------+---------+-------------------+
   |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?

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary WHERE num_movies > 5 ORDER BY avg_rank  DESC LIMIT 10;
   ```

<div id="creating-an-incremental-materialization">
  ## Criando uma materialização incremental
</div>

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](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/index#limitations) 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](https://en.wikipedia.org/wiki/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](https://docs.getdbt.com/docs/building-a-dbt-project/building-models/configuring-incremental-models#defining-a-uniqueness-constraint-optional).
   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](https://docs.getdbt.com/docs/building-a-dbt-project/building-models/configuring-incremental-models#filtering-rows-on-an-incremental-run).

   Atualize o arquivo `actor_summary.sql` da seguinte forma:

   ```sql theme={null}
   {{ 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](https://docs.getdbt.com/reference/dbt-jinja-functions/ref).

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

   ```response theme={null}
   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
   ```

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
   ```

   ```response theme={null}
   +------+------------+----------+------------------+------+---------+-------------------+
   |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`:

   ```sql theme={null}
   INSERT INTO imdb.actors VALUES (845466, 'Clicky', 'McClickHouse', 'M');
   ```

4. Vamos fazer com que "Clicky" estrele em 910 filmes aleatórios:

   ```sql theme={null}
   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:

   ```sql theme={null}
   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;
   ```

   ```response theme={null}
   +------+-------------------+----------+------------------+------+---------+-------------------+
   |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:

   ```response theme={null}
   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
   ```

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 2;
   ```

   ```response theme={null}
   +------+-------------------+----------+------------------+------+---------+-------------------+
   |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|
   +------+-------------------+----------+------------------+------+---------+-------------------+
   ```

<div id="internals">
  ### Aspectos internos
</div>

Podemos identificar as instruções executadas para realizar a atualização incremental acima consultando o log de consultas do ClickHouse.

```sql theme={null}
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:

<Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_05.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=21a9392d8a567b64531960cfc80b3de6" size="lg" alt="atualizações incrementais no dbt" width="1432" height="850" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_05.webp" />

Essa estratégia pode apresentar desafios em modelos muito grandes. Para mais detalhes, consulte [Limitações](/docs/pt-BR/integrations/connectors/data-ingestion/etl-tools/dbt/index#limitations).

<div id="append-strategy-inserts-only-mode">
  ### Estratégia Append (modo apenas inserções)
</div>

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:

   ```sql theme={null}
   {{ 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

   ```sql theme={null}
   INSERT INTO imdb.actors VALUES (845467, 'Danny', 'DeBito', 'M');
   ```

3. Vamos colocar Danny no elenco de 920 filmes aleatórios.

   ```sql theme={null}
   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

   ```response theme={null}
   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
   ```

   ```sql theme={null}
   SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 3;
   ```

   ```response theme={null}
   +------+-------------------+----------+------------------+------+---------+-------------------+
   |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:

```sql theme={null}
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.

<div id="deleteinsert-mode-experimental">
  ### Modo de exclusão e inserção (experimental)
</div>

Historicamente, o ClickHouse oferecia apenas suporte limitado a atualizações e exclusões, na forma de [mutações](/docs/pt-BR/reference/statements/alter/index) 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](/docs/pt-BR/reference/statements/delete), e o ClickHouse 25.7 introduziu as [atualizações leves](/docs/pt-BR/reference/statements/update). 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.

```sql theme={null}
{{ 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:

<Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_06.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=1544005a262e6b9249b99fc38e0138e8" size="lg" alt="incremental com exclusão leve" width="1345" height="528" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_06.webp" />

<div id="insert_overwrite-mode-experimental">
  ### modo `insert_overwrite` (experimental)
</div>

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.

<br />

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.

<Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/dbt/dbt_07.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=0486243c561a2ad6c335baec32014a65" size="lg" alt="insert overwrite incremental" width="7084" height="2327" data-path="images/integrations/data-ingestion/etl-tools/dbt/dbt_07.webp" />

<div id="creating-a-snapshot">
  ## Criando um snapshot
</div>

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](https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2:_add_new_row), 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](#creating-an-incremental-materialization). Certifique-se de que seu actor\_summary.sql não defina inserts\_only=True. Seu models/actor\_summary.sql deve ficar assim:

```sql theme={null}
   {{ 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.

   ```bash theme={null}
    touch snapshots/actor_summary.sql
   ```

2. Atualize o conteúdo do arquivo actor\_summary.sql com o conteúdo a seguir:
   ```sql theme={null}
   {% 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](#creating-an-incremental-materialization)) 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](https://docs.getdbt.com/docs/building-a-dbt-project/snapshots#check-strategy). 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).

3. Execute o comando `dbt snapshot`.

   ```response theme={null}
   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).

4. 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.

   ```sql theme={null}
   SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;
   ```

   ```response theme={null}
   +------+----------+------------+----------+-------------------+------------+
   |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        |
   +------+----------+------------+----------+-------------------+------------+
   ```

5. Faça nosso ator favorito, Clicky McClickHouse, aparecer em outros 10 filmes.

   ```sql theme={null}
   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;
   ```

6. 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.

   ```response theme={null}
   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
   ```

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

   ```sql theme={null}
   SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;
   ```

   ```response theme={null}
   +------+----------+------------+----------+-------------------+-------------------+
   |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](https://docs.getdbt.com/docs/building-a-dbt-project/snapshots).

<div id="using-seeds">
  ## Usando seeds
</div>

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](/docs/pt-BR/concepts/features/dictionaries/index), 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`:

   ```bash theme={null}
   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.

   ```bash theme={null}
   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:

   ```sql theme={null}
   SELECT * FROM imdb_dbt.genre_codes LIMIT 10;
   ```

   ```response theme={null}
   +-------+----+
   |genre  |code|
   +-------+----+
   |Drama  |DRA |
   |Romance|ROM |
   |Short  |SHO |
   |Mystery|MYS |
   |Adult  |ADU |
   |Family |FAM |

   |Action |ACT |
   |Sci-Fi |SCI |
   |Horror |HOR |
   |War    |WAR |
   +-------+----+=
   ```

<div id="further-information">
  ## Mais informações
</div>

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](https://docs.getdbt.com/docs/introduction).
