Skip to main content
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, 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: Usamos um subconjunto dessas tabelas, como mostrado. Crie as tabelas a seguir:
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.
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:
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:
A resposta deve ser assim:
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.
  2. Entre na pasta do seu projeto com cd:
  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:
  4. Atualize o arquivo dbt_project.yml para especificar nosso primeiro modelo, actor_summary, e defina o profile como clickhouse_imdb.
  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.
    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.
    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:
  2. Crie um novo arquivo em actors, dentro da pasta models. Aqui, criamos arquivos, cada um representando um modelo de ator:
  3. Crie os arquivos schema.yml e actor_summary.sql na pasta models/actors.
    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:
    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:
    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.
  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.
    Ao consultar esta view, podemos reproduzir os resultados da nossa consulta anterior com uma sintaxe mais simples:

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:
  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.
  3. Confirme a criação da tabela imdb_dbt.actor_summary:
    Você deverá ver a tabela com os tipos de dados apropriados:
  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:
    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?

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:
    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:
  3. Agora vamos adicionar dados ao nosso modelo para ilustrar uma atualização incremental. Adicione nosso ator “Clicky McClickHouse” à tabela actors:
  4. Vamos fazer com que “Clicky” estrele em 910 filmes aleatórios:
  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:
  6. Execute um dbt run e confirme que nosso modelo foi atualizado e corresponde aos resultados acima:

Aspectos internos

Podemos identificar as instruções executadas para realizar a atualização incremental acima consultando o log de consultas do ClickHouse.
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: 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:
  2. Vamos adicionar mais um ator famoso: Danny DeBito
  3. Vamos colocar Danny no elenco de 920 filmes aleatórios.
  4. Execute um dbt run e confirme que Danny foi adicionado à tabela actor_summary
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:
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.
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:

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.

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:
  1. Crie um arquivo actor_summary no diretório snapshots.
  2. Atualize o conteúdo do arquivo actor_summary.sql com o conteúdo a seguir:
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.
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.
  2. Faça nosso ator favorito, Clicky McClickHouse, aparecer em outros 10 filmes.
  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.
  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.
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:
  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.
  3. Confirme que os dados foram carregados:

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.
Última modificação em 24 de julho de 2026