Pular para o conteúdo principal
Uma materialização materialized_view deve ser um SELECT a partir de uma tabela de origem existente. Diferentemente do PostgreSQL, uma visão materializada no ClickHouse não é “estática” (e não tem uma operação REFRESH correspondente). Em vez disso, ela atua como um gatilho de inserção, inserindo novas linhas em uma tabela de destino ao aplicar a transformação SELECT definida às linhas inseridas na tabela de origem. Consulte a documentação sobre visões materializadas no ClickHouse para mais detalhes sobre como as visões materializadas funcionam no ClickHouse.
Para conceitos gerais de materialização e configurações compartilhadas (engine, order_by, partition_by etc.), consulte a página Materializações.

Como a tabela de destino é gerenciada

Quando você usa a materialização materialized_view, o dbt-clickhouse precisa criar tanto uma visão materializada quanto uma tabela de destino na qual as linhas transformadas são inseridas. Há duas formas de gerenciar a tabela de destino: A abordagem escolhida afeta como mudanças de esquema, full refreshes e configurações com múltiplas MVs são tratadas. As seções a seguir descrevem cada abordagem em detalhes.

Materialização com destino implícito

Este é o comportamento padrão. Quando você define um modelo materialized_view, o adaptador irá:
  1. Criar uma tabela de destino com o nome do modelo
  2. Criar uma visão materializada no ClickHouse com o nome <model_name>_mv
O esquema da tabela de destino é inferido a partir das colunas na instrução SELECT da MV. Todos os recursos (tabela de destino + MVs) compartilham a mesma configuração do modelo.
Consulte o arquivo de teste para mais exemplos.
Você também pode definir codec e ttl no nível da coluna da tabela de destino ao impor um contrato de modelo. Consulte Configuração de coluna para mais detalhes.

Múltiplas visões materializadas

O ClickHouse permite que mais de uma visão materializada grave registros na mesma tabela de destino. Para dar suporte a isso no dbt-clickhouse com a abordagem de destino implícito, você pode construir uma UNION no arquivo do modelo, envolvendo o SQL de cada visão materializada com comentários no formato --my_mv_name:begin e --my_mv_name:end. Por exemplo, o seguinte criará duas visões materializadas, ambas gravando dados na mesma tabela de destino do modelo. Os nomes das visões materializadas terão o formato <model_name>_mv1 e <model_name>_mv2:
Ao atualizar um modelo com várias visões materializadas (MVs), especialmente ao renomear uma das MVs, o dbt-clickhouse não remove automaticamente a MV antiga. Em vez disso, você verá o seguinte aviso:Warning - Table <previous table name> was detected with the same pattern as model name <your model name> but was not found in this run. In case it is a renamed mv that was previously part of this model, drop it manually (!!!)

Como iterar o esquema da tabela de destino

A partir da versão 1.9.8 do dbt-clickhouse, você pode controlar como o esquema da tabela de destino é atualizado quando dbt run encontra colunas diferentes no SQL da MV.
Por padrão, o dbt não aplicará nenhuma alteração à tabela de destino (valor da configuração ignore), mas você pode alterar essa configuração para seguir o mesmo comportamento da configuração on_schema_change em modelos incrementais. Além disso, você pode usar essa configuração como um mecanismo de proteção. Se defini-la como fail, a compilação falhará se as colunas no SQL da MV forem diferentes das da tabela de destino criada na primeira execução de dbt run.

Carga retroativa de dados

Por padrão, ao criar ou recriar uma visão materializada (MV), a tabela de destino é preenchida primeiro com os dados históricos antes de a própria MV ser criada (catchup=True). Você pode desativar esse comportamento definindo a configuração catchup como False.
Risco de perda de dados com Full RefreshUsar catchup: False com dbt run --full-refresh descartará todos os dados existentes na tabela de destino. A tabela será recriada vazia e passará a capturar apenas novos dados. Certifique-se de ter backups caso os dados históricos possam ser necessários mais tarde.

Materialização com destino explícito (Beta)

BetaEste recurso está em beta e está disponível a partir da versão 1.10 do dbt-clickhouse. A API pode mudar com base no feedback da comunidade.
Por padrão, o dbt-clickhouse cria e gerencia tanto a tabela de destino quanto as visões materializadas em um único modelo (a abordagem de destino implícito descrita acima). Essa abordagem tem algumas limitações:
  • Todos os recursos (tabela de destino + MVs) compartilham a mesma configuração. Se várias MVs apontarem para a mesma tabela de destino, elas deverão ser definidas em conjunto usando a sintaxe UNION ALL.
  • Nenhum desses recursos pode ser tratado separadamente; todos precisam ser gerenciados usando o mesmo arquivo de modelo.
  • Você não consegue controlar facilmente o nome de cada MV.
  • Todas as configurações são compartilhadas entre a tabela de destino e as MVs, o que dificulta configurar cada recurso individualmente e entender qual configuração pertence a cada um.
O recurso de destino explícito permite definir a tabela de destino separadamente como uma materialização table comum e, em seguida, referenciá-la a partir dos seus modelos de visão materializada.

Benefícios

  • Recursos totalmente separados: Agora cada recurso pode ser definido separadamente, melhorando a legibilidade.
  • Recursos 1:1 entre dbt e CH: Agora você pode usar as ferramentas do dbt para gerenciá-los e iterar sobre eles separadamente.
  • Diferentes configurações agora disponíveis: Agora é possível aplicar uma configuração diferente a cada um deles.
  • Não é mais necessário seguir convenções de nomenclatura: Agora todos os recursos são criados com o nome que você definir, e não com o nome personalizado adicionado com _mv para as MVs.

Limitações

  • A definição da tabela de destino não é algo natural no dbt: não é um SQL que vai ler de uma tabela de origem, então você perde as validações do dbt nesse ponto. O SQL da MV ainda será validado usando os utilitários do dbt, e a compatibilidade dele com as colunas da tabela de destino será validada no nível do CH.
  • Encontramos alguns problemas relacionados às limitações da função ref(): precisamos usá-la para referenciar modelos entre si, mas ela só pode ser usada para referenciar modelos upstream, não downstream. Isso traz alguns problemas para esta implementação. Criamos uma issue no repositório dbt-core e, no momento, estamos conversando com eles para buscar possíveis soluções (dbt-labs/dbt-core#12319):
    • Quando ref() é chamada de dentro do bloco de configuração, ela retorna o modelo atual, e não o modelo compartilhado. Isso nos impede de defini-la na seção config(), obrigando-nos a usar um comentário para adicionar essa dependência. Estamos seguindo o mesmo padrão definido na documentação do dbt com a abordagem “—depends_on:”.
    • ref() funciona no nosso caso, pois força a criação da tabela de destino primeiro, mas, no gráfico de dependências da documentação gerada, a tabela de destino aparecerá como mais uma dependência upstream, e não downstream, o que dificulta um pouco o entendimento.
    • unit-test também nos obriga a definir alguns dados para a tabela de destino, mesmo quando a ideia não é ler dela. A solução alternativa é simplesmente deixar vazios os dados dessa tabela.

Uso

Passo 1: Defina a tabela de destino como um modelo de tabela comum Model events_daily.sql:
Esta é a solução alternativa que mencionamos na seção de limitações. Você pode perder algumas validações do dbt aqui, mas o schema ainda será validado pelo ClickHouse. Etapa 2: Defina visões materializadas apontando para a tabela de destino Por exemplo, você pode definir MVs diferentes em modelos diferentes desta forma, inclusive apontando para a mesma tabela de destino. Observe a nova chamada da macro {{ materialization_target_table(ref('events_daily')) }}, que configura a tabela de destino da MV. Modelo page_events_aggregator.sql:
Modelo mobile_events_aggregator.sql:

Opções de configuração

Ao usar tabelas de destino explícitas, além das configurações gerais de materialização e das configurações específicas da tabela, aplicam-se as seguintes configurações: Na tabela de destino (materialized='table'): Na visão materializada (materialized='materialized_view'):
Em geral, convém definir apenas catchup como True nas MVs ou repopulate_from_mvs_on_full_refresh como True nas tabelas de destino correspondentes. Se você definir ambos como True, isso pode duplicar dados.

Operações comuns

Atualização completa com tabelas de destino explícitas

Ao usar --full-refresh, as tabelas de destino explícitas serão recriadas (portanto, você poderá perder dados se a ingestão estiver em andamento durante esse processo). O comportamento varia de acordo com a sua configuração: Opção 1: comportamento padrão do --full-refresh. Tudo é recriado, mas, durante a recriação das MVs, a tabela de destino ficará vazia ou parcialmente carregada. Tudo é removido e recriado. Se você quiser reinserir os dados usando o SQL das MVs, mantenha a configuração catchup=True:
Opção 2: Quero recriar a tabela de destino e não quero ler dados vazios enquanto as MVs estão sendo recriadas. Se você precisar primeiro atualizar o SQL das MVs, pode definir catchup=False nelas e depois executar um dbt run ou dbt run --full-refresh nas MVs. Certifique-se de que as MVs sejam criadas antes de executar --full-refresh na tabela de destino, pois isso usa as definições das MVs do ClickHouse. Defina repopulate_from_mvs_on_full_refresh=True no modelo da tabela de destino. Em um dbt run --full-refresh, isso irá:
  1. Criar uma nova tabela temporária
  2. Executar INSERT-SELECT usando o SQL de cada MV
  3. Trocar as tabelas atomicamente
Assim, sua tabela não ficará vazia enquanto as MVs estiverem sendo recriadas.

Alterando a tabela de destino

Você não pode alterar a tabela de destino de uma MV sem usar --full-refresh. Se tentar executar um dbt run normal após alterar a referência materialization_target_table(), a compilação falhará com uma mensagem de erro indicando que o destino foi alterado. Para alterar o destino:
  1. Atualize a chamada materialization_target_table()
  2. Execute dbt run --full-refresh -s your_mv_model

Solução de problemas comuns

A tabela de destino fica vazia durante/após a execução de run

Há alguns motivos pelos quais isso pode acontecer:
  • As visões materializadas podem estar configuradas com catchup=False ou a tabela de destino pode estar configurada com repopulate_from_mvs_on_full_refresh=False, portanto nenhuma carga retroativa é executada quando as visões materializadas são criadas ou quando a tabela de destino é recriada. Esse é o comportamento esperado. Portanto, se você quiser reinserir os dados usando o SQL das visões materializadas, defina catchup=True na visão materializada (esse é o valor padrão) ou repopulate_from_mvs_on_full_refresh=True na tabela de destino. Certifique-se de não ativar os dois ao mesmo tempo para evitar duplicatas. Consulte a seção de configuração para mais detalhes.
  • Durante a execução de dbt run --full-refresh, se as visões materializadas usarem o padrão catchup=True, o destino será recriado e as MVs reinserirão os dados sequencialmente. Para evitar essa situação, consulte Atualização completa com destinos explícitos.

dbt run --full-refresh em uma tabela de destino com repopulate_from_mvs_on_full_refresh=True usa a lógica de versões antigas de visões materializadas, e não o SQL que está atualmente no projeto

repopulate_from_mvs_on_full_refresh=True usa o SQL existente da MV já definido no ClickHouse. Para garantir que a nova definição da visão materializada seja usada, execute um dbt run para cada visão materializada antes de executar dbt run --full-refresh na tabela de destino.

Há dados duplicados após a execução de um run

Possíveis motivos:
  • Tanto catchup=True nas visões materializadas quanto repopulate_from_mvs_on_full_refresh=True na tabela de destino podem estar habilitados: mantenha apenas um deles, dependendo das operações que pretende executar. Consulte a seção de configuração para mais detalhes.
  • A tabela de destino não foi definida com WHERE 0: a tabela de destino deve ser criada vazia, mas a consulta interna pode inserir dados se WHERE 0 não for incluído. Certifique-se de que a cláusula esteja incluída.

Perda de dados durante a ingestão ativa após a execução de um dbt run --full-refresh

Algumas linhas da tabela de origem ficam ausentes na tabela de destino após a execução de um dbt run --full-refresh. As visões materializadas do ClickHouse funcionam como gatilhos de inserção — elas só capturam dados enquanto existem. Durante um full refresh, há uma breve janela em que a MV é removida e recriada (a “janela cega”). Quaisquer linhas inseridas na tabela de origem durante essa janela não são capturadas. Consulte a seção Comportamento durante a ingestão ativa para mais detalhes.

Técnicas de depuração

Verifique o destino atual de uma MV no ClickHouse

Consulte system.tables para ver para onde uma visão materializada está gravando:

Verifique se o dbt reconhece uma tabela como tabela de destino de uma visão materializada

Durante a execução do dbt, procure por esta mensagem de log:
A tabela <table_name> está sendo usada como tabela de destino por uma visão materializada gerenciada pelo dbt. Definindo mv_on_schema_change como “fail” por padrão para evitar perda de dados.
Se esta mensagem aparecer, o dbt detectou que a tabela é a tabela de destino de pelo menos uma visão materializada gerenciada pelo dbt. Se você espera ver essa mensagem, mas ela não aparecer, verifique se:
  • O modelo da visão materializada define {{ materialization_target_table(ref('your_target')) }} corretamente
  • O modelo da visão materializada tem materialized='materialized_view' na configuração
  • Tanto a visão materializada quanto a tabela de destino foram executadas pelo menos uma vez

Migrando de destino implícito para destino explícito

Se você já tem modelos de visão materializada usando a abordagem de destino implícito e quer migrar para a abordagem de destino explícito, siga estas etapas: 1. Crie o modelo da tabela de destino Crie um novo arquivo de modelo com materialized='table' que defina o mesmo esquema da tabela de destino da MV atual. Use uma cláusula WHERE 0 para criar uma tabela vazia. Use o mesmo nome do modelo atual de visão materializada implícita. A partir de agora, você poderá usar esse modelo para fazer iterações na tabela de destino.
2. Atualize seus modelos de MV Crie novos modelos que incluam, cada um, o SQL da MV e a chamada da macro materialization_target_table() apontando para a nova tabela de destino. Se você estava usando UNION ALL, remova essa parte e os comentários. Para os nomes dos modelos, você terá que seguir esta convenção de nomenclatura:
  • se apenas uma MV foi definida, ela terá o nome: <old_model_name>_mv
  • se várias MVs foram definidas, cada uma terá o nome: <old_model_name>_mv_<name_in_comments>
Antes, em my_model.sql (tabela de destino implícita, modelo único com UNION ALL):
Depois (destino explícito, arquivos de modelo separados):
3. Repita esse processo conforme necessário, seguindo as instruções da seção destino explícito.

Comparação de comportamento entre as abordagens de destino implícito e destino explícito

Como se comportam em geral

Comportamento durante a ingestão ativa

Ao iterar seus modelos, você precisa estar ciente de como as diferentes operações interagem com os dados que estão sendo inseridos:
  • Como as visões materializadas do ClickHouse atuam como gatilhos de inserção, elas só capturam dados enquanto existem. Se uma visão materializada for removida e recriada (por exemplo, durante um --full-refresh), quaisquer linhas inseridas na tabela de origem durante esse intervalo não serão processadas pela visão materializada. Isso é chamado de visão materializada “cega”.
  • Os diferentes processos de catchup se baseiam em operações INSERT INTO ... SELECT que usam o SQL das visões materializadas e são independentes do funcionamento delas. Depois que o INSERT começa, os novos dados não são capturados por ele, mas serão capturados pela visão materializada anexada.
A tabela a seguir resume a segurança de cada operação quando há inserções ativas na tabela de origem.

Operações de destino implícito

Operações com destino explícito

Modelos de visão materializada: Modelo de tabela de destino:
Recomendações para ambientes de produção com ingestão ativa
  • Pause a ingestão durante operações do dbt, se possível: isso tornará todas as operações seguras, e nenhum dado será perdido.
  • Use um engine com desduplicação, se possível (por exemplo, ReplacingMergeTree) na tabela de destino para lidar com possíveis duplicatas causadas por sobreposição no catch-up.
  • Prefira ALTER TABLE ... MODIFY QUERY (dbt run normal, sem --full-refresh) sempre que possível — isso é sempre seguro.
  • Fique atento a janelas problemáticas durante operações do dbt.

Visões Materializadas Atualizáveis

Visões Materializadas Atualizáveis são um tipo especial de visão materializada no ClickHouse que reexecuta periodicamente a consulta e armazena o resultado, de forma semelhante ao funcionamento das visões materializadas em outros bancos de dados. Isso é útil em cenários nos quais você precisa de snapshots ou agregações periódicas, em vez de gatilhos de inserção em tempo real.
Visões materializadas atualizáveis podem ser usadas com as duas abordagens: destino implícito e destino explícito. A configuração refreshable é independente de como a tabela de destino é gerenciada.
Para usar uma visão materializada atualizável, adicione um objeto de configuração refreshable ao seu modelo de MV com as seguintes opções:

Exemplo com destino implícito

Exemplo com destino explícito

Limitações

  • Ao criar uma visão materializada atualizável (MV) no ClickHouse que tenha uma dependência, o ClickHouse não gera um erro se a dependência especificada não existir no momento da criação. Em vez disso, a MV atualizável permanece em estado inativo, aguardando que a dependência seja atendida antes de começar a processar atualizações ou ser atualizada. Esse comportamento é intencional, mas pode causar atrasos na disponibilidade dos dados se a dependência necessária não for resolvida rapidamente. Garanta que todas as dependências estejam corretamente definidas e existam antes de criar uma visão materializada atualizável.
  • Até o momento, não há um “vínculo com o dbt” real entre a MV e suas dependências; portanto, a ordem de criação não é garantida.
  • O recurso de atualização não foi testado com várias MVs apontando para o mesmo modelo de destino.
Última modificação em 12 de junho de 2026