View normal
Sintaxe:View parametrizada
Views parametrizadas são semelhantes a views normais, mas podem ser criadas com parâmetros que não são resolvidos de imediato. Essas views podem ser usadas com funções de tabela, que especificam o nome da view como nome da função e os valores dos parâmetros como argumentos.system.columns.
Além disso, as consultas DESCRIBE só funcionariam se os parâmetros fossem fornecidos.
Visão materializada
OR REPLACE e IF NOT EXISTS são mutuamente excludentes: usá-los em conjunto resulta em erro de sintaxe.
CREATE OR REPLACE MATERIALIZED VIEW
CREATE OR REPLACE MATERIALIZED VIEW substitui atomicamente uma visão materializada existente e sua tabela de armazenamento interna (se houver). A operação requer um motor de banco de dados Atomic ou Replicated.
- Sem a cláusula
TO: a tabela interna antiga é excluída e uma nova é criada. Os dados existentes na tabela interna são perdidos, a menos quePOPULATEseja especificado. - Com a cláusula
TO: apenas a definição da VIEW é substituída; a tabela de destino e seus dados permanecem inalterados. - Compatível com
REFRESH,ON CLUSTERe todas as opções de motor.POPULATEé suportado apenas em bancos de dadosAtomic— ele é rejeitado em bancos de dadosReplicated(veja a observação sobrePOPULATEabaixo). - Requer os privilégios
CREATE VIEWeDROP VIEW.
CREATE OR REPLACE MATERIALIZED VIEW é suportado apenas com os motores de banco de dados Atomic ou Replicated. Não é compatível com o motor de banco de dados Ordinary.TO [db].[table], você deve especificar ENGINE — o motor de tabela usado para armazenar os dados.
Ao criar uma visão materializada com TO [db].[table], você também pode usar POPULATE para preencher retroativamente a tabela de destino com os dados de origem existentes (a tabela de destino já pode conter dados; nesse caso, as linhas preenchidas retroativamente são acrescentadas). POPULATE não pode ser combinado com REFRESH: uma visão materializada atualizável é preenchida por sua primeira atualização, portanto, POPULATE carregaria os dados iniciais duas vezes (use EMPTY para ignorar a primeira atualização).
Uma visão materializada é implementada da seguinte forma: ao inserir dados na tabela especificada em SELECT, parte dos dados inseridos é transformada por essa consulta SELECT, e o resultado é inserido na VIEW.
VIEWs materializadas no ClickHouse usam nomes de colunas em vez da ordem das colunas durante a inserção na tabela de destino. Se alguns nomes de colunas não estiverem presentes no resultado da consulta
SELECT, o ClickHouse usará um valor padrão, mesmo que a coluna não seja Nullable. Uma prática segura é adicionar aliases para todas as colunas ao usar VIEWs materializadas.VIEWs materializadas no ClickHouse funcionam mais como gatilhos de inserção. Se houver alguma agregação na consulta da VIEW, ela será aplicada apenas ao lote de dados recém-inseridos. Quaisquer alterações nos dados existentes da tabela de origem (como update, delete, drop partition etc.) não alteram a VIEW materializada.VIEWs materializadas no ClickHouse não têm comportamento determinístico em caso de erro. Isso significa que os blocos que já tiverem sido gravados serão preservados na tabela de destino, mas todos os blocos após o erro não serão.Por padrão, se o envio para uma das VIEWs gerar uma exceção, a consulta INSERT falhará. Não há garantia de que o bloco já tenha chegado à tabela de origem nesse ponto — isso depende do momento em que o pipeline de inserção estava, não do erro da VIEW. Tente novamente o INSERT com falha com desduplicação de inserção (insert_deduplicate, deduplicate_blocks_in_dependent_materialized_views) para obter entrega exactly-once para a tabela de origem e todas as VIEWs dependentes.Definir materialized_views_ignore_errors=true na consulta INSERT altera apenas o relatório de erros: cada erro de VIEW é registrado como um aviso e a consulta INSERT é bem-sucedida. A entrega ao destino da VIEW com falha é parcial — os blocos processados antes da exceção são mantidos, e o bloco com falha mais quaisquer blocos subsequentes são descartados dessa VIEW. As VIEWs a jusante desse destino veem apenas os blocos que realmente chegaram, então a entrega delas também é parcial. As VIEWs irmãs (e suas cadeias a jusante) que não geraram exceção são gravadas integralmente, e a tabela de origem é gravada como de costume. Como o INSERT informa sucesso, o cliente não recebe nenhum sinal de falha e nenhuma nova tentativa automática é acionada; use essa configuração apenas quando gravações na tabela de origem não puderem ser bloqueadas por problemas no lado da VIEW (por exemplo, tabelas system.*_log).materialized_views_ignore_errors é true por padrão para tabelas system.*_log.POPULATE, os dados existentes da tabela de origem serão inseridos na VIEW durante sua criação. Caso contrário, a VIEW conterá apenas os dados inseridos na tabela de origem após a criação da VIEW.
Para uma CREATE MATERIALIZED VIEW simples, POPULATE é atômico por padrão (configuração materialized_views_populate_atomically = 1): a VIEW passa a receber novas inserções na tabela de origem e um snapshot dos dados existentes é obtido simultaneamente, sob um breve bloqueio exclusivo na tabela de origem, para que cada linha inserida concorrentemente com o preenchimento seja entregue à VIEW exatamente uma vez — sem omissões nem duplicações. O preenchimento, possivelmente de longa duração, lê então o snapshot fixado sem manter nenhum bloqueio.
Essa é uma atomicidade local do caminho de inserção: o bloqueio exclusivo só serializa com inserções que adquirem o bloqueio de armazenamento dessa tabela de origem no mesmo servidor; portanto, a garantia de exatamente uma vez abrange inserções que chegam por este servidor. Não é uma garantia para todo o cluster — linhas inseridas em outra réplica de uma origem ReplicatedMergeTree ou por um caminho de gravação distribuído (por exemplo, em uma tabela Distributed ou via ON CLUSTER) concorrentemente com o preenchimento estão fora desse recorte e ainda podem ser omitidas ou duplicadas.
Se o preenchimento falhar — por exemplo, se o bloqueio exclusivo em uma tabela de origem ocupada não puder ser adquirido dentro de lock_acquire_timeout, ou se o SELECT da VIEW gerar uma exceção durante a execução — a VIEW recém-criada será excluída e a consulta CREATE falhará, sem deixar nada do que foi criado, portanto, ela poderá simplesmente ser tentada novamente. Para a forma TO [db].[table], essa reversão exclui apenas a VIEW, nunca a tabela de destino preexistente — mas as linhas que o preenchimento com falha já inseriu no destino permanecem lá, exatamente como após um INSERT ... SELECT com falha nessa tabela, portanto, tentar o CREATE novamente as insere outra vez. Se o preenchimento precisar ser exato, tente novamente em uma tabela de destino truncada ou nova, ou use um mecanismo de desduplicação como ReplacingMergeTree.
A atomicidade exige que a tabela de origem seja compatível com a leitura de um snapshot fixado em um ponto no tempo — a família
MergeTree e Memory. Para qualquer outra origem (uma VIEW, Distributed, Merge, Buffer, a família Log ou uma tabela que não esteja em um banco de dados Atomic), o preenchimento recorre ao comportamento legado, não atômico (registrado no log do servidor): os dados existentes são lidos com um snapshot separado e não coordenado, portanto, linhas inseridas durante o preenchimento podem ser perdidas ou duplicadas. Nesse caso, crie a VIEW e execute um INSERT ... SELECT separado se precisar de dados exatos. Definir materialized_views_populate_atomically = 0 força esse comportamento legado para todas as origens.O preenchimento atômico aplica-se apenas a CREATE MATERIALIZED VIEW simples. CREATE OR REPLACE / REPLACE MATERIALIZED VIEW ... POPULATE sempre usam o preenchimento legado, não atômico.POPULATE não é compatível com bancos de dados Replicated (use database_replicated_allow_heavy_create para contornar essa restrição) e não é compatível com ClickHouse Cloud. Quando é habilitado por meio dessa substituição, o preenchimento é sempre o legado, não atômico — um preenchimento com falha não poderia ser revertido de forma consistente em todas as réplicas.SELECT pode conter DISTINCT, GROUP BY, ORDER BY, LIMIT. Observe que as transformações correspondentes são realizadas de forma independente em cada bloco de dados inseridos. Por exemplo, se GROUP BY estiver definido, os dados serão agregados durante a inserção, mas apenas dentro de um único pacote de dados inseridos. Os dados não serão agregados posteriormente. A exceção é ao usar um ENGINE que realiza agregação de dados por conta própria, como SummingMergeTree.
Se a VIEW materializada usar a construção TO [db.]name, você pode fazer DETACH da VIEW, executar ALTER na tabela de destino e, em seguida, fazer ATTACH da VIEW previamente desanexada (DETACH).
As VIEWs têm a mesma aparência das tabelas normais. Por exemplo, elas são listadas no resultado da consulta SHOW TABLES.
Para excluir uma VIEW, use DROP VIEW. Embora DROP TABLE também funcione para VIEWs.
Segurança SQL
DEFINER e SQL SECURITY permitem especificar qual usuário do ClickHouse deve ser usado ao executar a consulta subjacente da visão.
SQL SECURITY tem três valores válidos: DEFINER, INVOKER ou NONE. Você pode especificar qualquer usuário existente ou CURRENT_USER na cláusula DEFINER.
A tabela a seguir mostra quais permissões são necessárias para cada usuário ao consultar uma visão.
Observe que, independentemente da opção de segurança SQL, em todos os casos ainda é necessário ter GRANT SELECT ON <view> para poder lê-la.
SQL SECURITY NONE é uma opção obsoleta. Qualquer usuário com permissões para criar visões com SQL SECURITY NONE poderá executar qualquer consulta arbitrária.
Portanto, é necessário ter GRANT ALLOW SQL SECURITY NONE TO <user> para criar uma visão com essa opção.DEFINER/SQL SECURITY não forem especificados, o resultado dependerá da configuração do servidor ignore_empty_sql_security_in_create_view_query.
Com seu valor padrão de true, a consulta é armazenada conforme escrita e a visão recebe um tipo de segurança SQL vazio. Uma view normal é então executada com as permissões do invocador e, para uma visão materializada com uma tabela de destino especificada explicitamente, as verificações de acesso nessa tabela de destino são ignoradas: inserir na tabela de origem não exige o privilégio INSERT na tabela de destino, e ler a visão não exige o privilégio SELECT nela.
Com false, os seguintes valores padrão são gravados na definição da visão no momento da criação:
SQL SECURITY:INVOKERpara views normais (configurável pordefault_normal_view_sql_security) eDEFINERpara visões materializadas (configurável pordefault_materialized_view_sql_security)DEFINER:CURRENT_USER(configurável pordefault_view_definer)
DEFINER/SQL SECURITY mantém o tipo de segurança SQL vazio.
Para alterar a segurança SQL de uma visão existente, use
Exemplos
Visualização em tempo real
Este recurso está obsoleto e será removido no futuro. Para sua conveniência, a documentação antiga está disponível aquivisão materializada atualizável
interval é uma sequência de intervalos simples:
REFRESH deve especificar pelo menos um de EVERY, AFTER ou DEPENDS ON. REFRESH isolado (sem nenhum deles) é rejeitado. REFRESH DEPENDS ON ... sem EVERY/AFTER é uma forma abreviada de REFRESH AFTER 0 SECOND DEPENDS ON ...; veja Dependências de atualização abaixo.
Executa periodicamente a consulta correspondente e armazena o resultado em uma tabela.
- Se
APPENDfor especificado, cada atualização insere linhas na tabela sem excluir as já existentes. A inserção não é atômica, assim como em uma consultaINSERT INTO ... SELECTcomum. - Se
APPEND INCREMENTALfor especificado, cada atualização executa a consulta apenas nas linhas confirmadas na tabela de origem desde a atualização anterior e adiciona o resultado. - Caso contrário, cada atualização substitui atomicamente o conteúdo anterior da tabela.
- Não há gatilho de inserção. Quando novos dados são inseridos na tabela especificada em
SELECT, eles não são enviados automaticamente para a visão materializada atualizável. Em vez disso, a inserção de dados ocorre apenas durante execuções de atualização periódicas ou manuais. - Não há restrições para a consulta
SELECT. Funções de tabela (por exemplo,url()), VIEWs, UNION e JOIN são permitidos.APPEND INCREMENTALé a única exceção: ele requer uma única tabela de origemMergeTreesimples comenable_block_number_column = 1eenable_block_offset_column = 1e rejeitaJOIN,UNION, subconsultas, VIEWs e funções de tabela.
As configurações na parte
REFRESH ... SETTINGS da consulta são configurações de atualização (por exemplo, refresh_retries), distintas das configurações comuns (por exemplo, max_threads). As configurações comuns podem ser especificadas com SETTINGS no final da consulta.Programação de atualização
Exemplos de programação de atualização:RANDOMIZE FOR ajusta aleatoriamente o momento de cada atualização, por exemplo:
REFRESH EVERY 1 MINUTE levar 2 minutos para ser atualizada, ela simplesmente passará a ser atualizada a cada 2 minutos. Se depois ficar mais rápida e passar a ser atualizada em 10 segundos, voltará a ser atualizada a cada minuto. (Em particular, ela não será atualizada a cada 10 segundos para compensar um acúmulo de atualizações perdidas — esse acúmulo não existe.)
Normalmente, a primeira atualização é iniciada imediatamente após a criação da VIEW materializada: o tempo desde a última atualização é infinito, então qualquer agendamento indica que é hora de atualizar agora. Se EMPTY for especificado, essa atualização inicial será ignorada, e a primeira atualização ocorrerá no próximo horário agendado; por exemplo, para EVERY 1 HOUR, a primeira atualização ocorrerá no fim da hora atual.
Em banco de dados Replicated
Se a view materializada atualizável estiver em um banco de dados Replicated, as réplicas se coordenam entre si para que apenas uma delas execute a atualização em cada horário agendado. O motor de tabela ReplicatedMergeTree é necessário para que todas as réplicas vejam os dados produzidos pela atualização. No modoAPPEND, a coordenação pode ser desativada com SETTINGS all_replicas = 1. Isso faz com que as réplicas executem as atualizações de forma independente. Nesse caso, o ReplicatedMergeTree não é necessário.
No modo sem APPEND, apenas a atualização coordenada é compatível. Para atualização não coordenada, use o banco de dados Atomic e a consulta CREATE ... ON CLUSTER para criar views materializadas atualizáveis em todas as réplicas.
A coordenação é feita por meio do Keeper. O caminho do znode é determinado pela configuração do servidor default_replica_path.
Dependências de atualização
DEPENDS ON sincroniza as atualizações de diferentes tabelas:
DEPENDS ON funciona apenas entre VIEWs materializadas atualizáveis. Em particular, se a VIEW de dependência usar TO <table>, certifique-se de usar o nome da VIEW, e não o da tabela. Se a lista de DEPENDS ON contiver uma tabela comum, uma VIEW não atualizável ou um erro de digitação, a VIEW nunca será atualizada e exibirá o estado MissingDependencies em system.view_refreshes. As dependências podem ser alteradas ou removidas com ALTER; consulte Alterando os parâmetros de atualização.Usando DEPENDS ON para manter a latência de propagação consistente
Se ambas as VIEWs usarem REFRESH EVERY com o mesmo período, a dependência será aplicada em cada intervalo de tempo.
Por exemplo, suponha que as VIEWs X e Y usem REFRESH EVERY 1 HOUR e que Y leia da tabela de saída de X. Sem dependências, Y normalmente veria os dados da atualização de X da hora anterior. Com DEPENDS ON X, a atualização das 11:00 de Y só começará depois que a atualização das 11:00 de X for concluída.
Usando DEPENDS ON para processamento em lote de streams
SeREFRESH EVERY não for usado, a VIEW dependente X será atualizada se todas as suas dependências tiverem sido atualizadas pelo menos uma vez desde a última atualização de X. REFRESH AFTER T adiciona um atraso: a dependente iniciará a atualização T unidades de tempo após a dependência concluir uma atualização.
Dependências circulares são permitidas e úteis. Considere este grafo de VIEWs materializadas atualizáveis:
- X pega um lote de linhas de algum stream e as coloca em uma tabela.
- Em seguida, Y e Z leem dessa tabela, fazem agregações diferentes e acrescentam os resultados a outras tabelas.
- Depois que o lote for totalmente processado, X pega o próximo lote, e o ciclo se repete.
SYSTEM REFRESH VIEW manual após cada reinicialização, em vez de apenas uma vez após a criação das VIEWs.
Configurações de atualização
Configurações de atualização disponíveis:refresh_retries- Quantas vezes tentar novamente se a consulta de atualização falhar com uma exceção. Se todas as tentativas falharem, a atualização será adiada para o próximo horário agendado. 0 significa nenhuma tentativa adicional; -1 significa tentativas infinitas. Padrão: 2.refresh_retry_initial_backoff_ms- Atraso antes da primeira tentativa de repetição, serefresh_retriesnão for zero. Cada nova tentativa dobra esse atraso, atérefresh_retry_max_backoff_ms. Padrão: 100 ms.refresh_retry_max_backoff_ms- Limite para o crescimento exponencial do atraso entre tentativas de atualização. Padrão: 60000 ms (1 minuto).all_replicas- Em um banco de dados Replicated comAPPEND, controla se todas as réplicas são atualizadas de forma independente ou se apenas uma réplica é atualizada em cada horário agendado. Não pode ser alterado após a criação da VIEW. Padrão:false.
Alterando os parâmetros de atualização
Os parâmetros de atualização de uma view materializada atualizável existente podem ser alterados comALTER TABLE ... MODIFY REFRESH:
EVERY ou AFTER) é obrigatório: a instrução sempre substitui todos os parâmetros de atualização — agendamento, RANDOMIZE FOR, DEPENDS ON e configurações de atualização — pelos valores especificados. Tudo o que for omitido é redefinido para o valor padrão (configurações) ou removido (dependências, aleatorização).
-
Para alterar apenas as configurações de atualização (por exemplo,
refresh_retries), repita o agendamento atual: -
ALTER TABLE ... MODIFY SETTING refresh_retries = ...não tem suporte em visões materializadas; é preciso usarMODIFY REFRESH. -
Não há suporte para alterar o modo de atualização:
APPENDeINCREMENTALnão podem ser adicionados nem removidos. -
A configuração
all_replicasnão pode ser alterada após a criação.
Outras operações
O status de todas as visões materializadas atualizáveis está disponível na tabelasystem.view_refreshes. Ela contém, em particular, o progresso da atualização (se estiver em execução), os horários da última e da próxima atualização e a mensagem de exceção caso uma atualização falhe.
Para interromper, iniciar, disparar ou cancelar atualizações manualmente, use SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW.
Para aguardar a conclusão de uma atualização, use SYSTEM WAIT VIEW. Isso é útil, em particular, para aguardar a atualização inicial após criar uma view.
Curiosidade: a consulta de atualização pode ler da view que está sendo atualizada, visualizando a versão dos dados anterior à atualização. Isso significa que você pode implementar o jogo da vida de Conway: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
Conteúdo relacionado
- Blog: Trabalhando com dados de séries temporais no ClickHouse
- Blog: Criando uma solução de observabilidade com ClickHouse - Parte 2 - Traces
Views temporárias
O ClickHouse oferece suporte a views temporárias com as seguintes características (correspondentes às tabelas temporárias, quando aplicável):- Duração da sessão Uma view temporária existe apenas durante a sessão atual. Ela é removida automaticamente quando a sessão termina.
- Sem banco de dados Você não pode qualificar uma view temporária com o nome de um banco de dados. Ela existe fora dos bancos de dados (espaço de nomes da sessão).
-
Não replicado / sem ON CLUSTER
Objetos temporários são locais à sessão e não podem ser criados com
ON CLUSTER. - Resolução de nomes Se um objeto temporário (tabela ou view) tiver o mesmo nome de um objeto persistente e uma consulta referenciar esse nome sem um banco de dados, o objeto temporário será usado.
-
Objeto lógico (sem armazenamento)
Uma view temporária armazena apenas o texto do seu
SELECT(usa internamente o armazenamentoView). Ela não persiste dados e não aceitaINSERT. -
Cláusula de engine
Você não precisa especificar
ENGINE; se ele for informado comoENGINE = View, será ignorado/tratado como a mesma view lógica. -
Segurança / privilégios
Criar uma view temporária exige o privilégio
CREATE TEMPORARY VIEW, que é concedido implicitamente porCREATE VIEW. -
SHOW CREATE
Use
SHOW CREATE TEMPORARY VIEW view_name;para exibir o DDL de uma view temporária.
Sintaxe
OR REPLACE não tem suporte para views temporárias (para manter a consistência com as tabelas temporárias). Se você precisar “substituir” uma view temporária, exclua-a e crie-a novamente.
Exemplos
Crie uma tabela-fonte temporária e uma view temporária sobre ela:Não permitidos / limitações
CREATE OR REPLACE TEMPORARY VIEW ...→ não permitido (useDROP+CREATE).CREATE TEMPORARY MATERIALIZED VIEW ...→ não permitido.CREATE TEMPORARY VIEW db.view AS ...→ não permitido (sem qualificador de banco de dados).CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ não permitido (objetos temporários são locais da sessão).POPULATE,REFRESH,TO [db.table], motores internos e todas as cláusulas específicas de MV → não se aplicam a views temporárias.
Notas sobre consultas distribuídas
Uma view temporária é apenas uma definição; não há dados para transferir. Se sua view temporária fizer referência a tabelas temporárias (por exemplo,Memory), os dados delas podem ser enviados a servidores remotos durante a execução de consultas distribuídas, da mesma forma que acontece com as tabelas temporárias.