> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentação do CREATE VIEW

# CREATE VIEW

export const DeprecatedBadge = () => {
  return <div className="deprecatedBadge">
            <div className="deprecatedIcon">
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M13 0H1C0.734784 0 0.48043 0.105357 0.292893 0.292893C0.105357 0.48043 0 0.734784 0 1V2.5C0 2.76522 0.105357 3.01957 0.292893 3.20711C0.48043 3.39464 0.734784 3.5 1 3.5V9C1 9.26522 1.10536 9.51957 1.29289 9.70711C1.48043 9.89464 1.73478 10 2 10H12C12.2652 10 12.5196 9.89464 12.7071 9.70711C12.8946 9.51957 13 9.26522 13 9V3.5C13.2652 3.5 13.5196 3.39464 13.7071 3.20711C13.8946 3.01957 14 2.76522 14 2.5V1C14 0.734784 13.8946 0.48043 13.7071 0.292893C13.5196 0.105357 13.2652 0 13 0ZM12 9H2V3.5H12V9ZM13 2.5H1V1H13V2.5ZM5 5.5C5 5.36739 5.05268 5.24021 5.14645 5.14645C5.24021 5.05268 5.36739 5 5.5 5H8.5C8.63261 5 8.75979 5.05268 8.85355 5.14645C8.94732 5.24021 9 5.36739 9 5.5C9 5.63261 8.94732 5.75979 8.85355 5.85355C8.75979 5.94732 8.63261 6 8.5 6H5.5C5.36739 6 5.24021 5.94732 5.14645 5.85355C5.05268 5.75979 5 5.63261 5 5.5Z" fill="currentColor" />
            </svg>
        </div>
            Recurso obsoleto
        </div>;
};

Cria uma nova VIEW. As VIEWs podem ser [normais](#normal-view), [visões materializadas](#materialized-view) e [VIEWs materializadas atualizáveis](#refreshable-materialized-view).

## View normal

Sintaxe:

```sql theme={null}
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

Views normais não armazenam dados. Elas apenas leem de outra tabela a cada acesso. Em outras palavras, uma view normal nada mais é do que uma consulta salva. Ao consultar uma view, essa consulta salva é usada como uma subconsulta na cláusula [FROM](/pt-BR/reference/statements/select/from).

Como exemplo, suponha que você tenha criado uma view:

```sql theme={null}
CREATE VIEW view AS SELECT ...
```

e escrever uma consulta:

```sql theme={null}
SELECT a, b, c FROM view
```

Esta consulta é totalmente equivalente ao uso da subconsulta:

```sql theme={null}
SELECT a, b, c FROM (SELECT ...)
```

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

```sql theme={null}
CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
```

O comando acima cria uma view para a tabela, que pode ser usada como função de tabela substituindo os parâmetros, como mostrado abaixo.

```sql theme={null}
SELECT * FROM view(column1=value1, column2=value2 ...)
```

Como a view parametrizada depende dos valores dos parâmetros, ela não tem um esquema quando os parâmetros não são fornecidos.
Isso significa que não há informações sobre views parametrizadas na tabela `system.columns`.
Além disso, as consultas `DESCRIBE` só funcionariam se os parâmetros fossem fornecidos.

```sql theme={null}
DESCRIBE view(column1=value1, column2=value2 ...)
```

## Visão materializada

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

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

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]name [ON CLUSTER cluster]
[TO [db.]target_table]
[ENGINE = engine]
[POPULATE]
[REFRESH ...]
AS SELECT ...
```

Principais comportamentos:

* **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 que `POPULATE` seja 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 CLUSTER` e todas as opções de motor. `POPULATE` é suportado apenas em bancos de dados `Atomic` — ele é rejeitado em bancos de dados `Replicated` (veja a observação sobre `POPULATE` abaixo).
* Requer os privilégios `CREATE VIEW` e `DROP VIEW`.

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

**Exemplos:**

```sql theme={null}
-- Create a materialized view with an inner table
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, sum(y) AS total FROM src GROUP BY x;

-- Replace with a new definition (old inner table data is lost)
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, count() AS cnt FROM src GROUP BY x;

-- Replace with POPULATE to backfill from existing source data
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    POPULATE
    AS SELECT x FROM src;

-- Replace an inner-table MV with a TO-table MV (target data is preserved)
CREATE OR REPLACE MATERIALIZED VIEW mv TO target
    AS SELECT x FROM src;
```

<Tip>
  Aqui está um guia passo a passo sobre como usar [visões materializadas](/pt-BR/concepts/features/materialized-views/cascading-materialized-views).
</Tip>

visões materializadas armazenam dados transformados pela consulta [SELECT](/pt-BR/reference/statements/select/index) correspondente.

Ao criar uma visão materializada sem `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](#refreshable-materialized-view) é 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.

<Note>
  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](/pt-BR/reference/data-types/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`.
</Note>

Se você especificar `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`.

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

Uma consulta `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](/pt-BR/reference/statements/drop#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.

| Opção de segurança SQL | Visão | Visão materializada |
| - | - | - |
| `DEFINER alice` | `alice` deve ter o privilégio `SELECT` na tabela de origem da visão. | `alice` deve ter o privilégio `SELECT` na tabela de origem da visão e o privilégio `INSERT` na tabela de destino da visão. |
| `INVOKER` | O usuário deve ter o privilégio `SELECT` na tabela de origem da visão. | `SQL SECURITY INVOKER` não pode ser especificado para visões materializadas. |
| `NONE` | - | - |

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

Se `DEFINER`/`SQL SECURITY` não forem especificados, o resultado dependerá da configuração do servidor [`ignore_empty_sql_security_in_create_view_query`](/pt-BR/reference/settings/server-settings/settings/other#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`: `INVOKER` para views normais (configurável por [`default_normal_view_sql_security`](/pt-BR/reference/settings/session-settings/default#default_normal_view_sql_security)) e `DEFINER` para visões materializadas (configurável por [`default_materialized_view_sql_security`](/pt-BR/reference/settings/session-settings/default#default_materialized_view_sql_security))
* `DEFINER`: `CURRENT_USER` (configurável por [`default_view_definer`](/pt-BR/reference/settings/session-settings/default#default_view_definer))

Views materializadas atualizáveis sempre recebem esses valores padrão, independentemente da configuração.

Uma visão mantém o tipo de segurança SQL de sua definição armazenada quando é anexada ou recarregada na inicialização do servidor, portanto, uma visão armazenada sem `DEFINER`/`SQL SECURITY` mantém o tipo de segurança SQL vazio.

Para alterar a segurança SQL de uma visão existente, use

```sql theme={null}
ALTER TABLE MODIFY SQL SECURITY { DEFINER | INVOKER | NONE } [DEFINER = { user | CURRENT_USER }]
```

### Exemplos

```sql theme={null}
CREATE VIEW test_view
DEFINER = alice SQL SECURITY DEFINER
AS SELECT ...
```

```sql theme={null}
CREATE VIEW test_view
SQL SECURITY INVOKER
AS SELECT ...
```

## Visualização em tempo real

<DeprecatedBadge />

Este recurso está obsoleto e será removido no futuro.

Para sua conveniência, a documentação antiga está disponível [aqui](https://pastila.nl/?00f32652/fdf07272a7b54bda7e13b919264e449f.md)

## visão materializada atualizável

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
REFRESH [EVERY|AFTER interval [OFFSET interval]]
[RANDOMIZE FOR interval]
[DEPENDS ON [db.]name [, [db.]name [, ...]]]
[SETTINGS name = value [, name = value [, ...]]]
[APPEND [INCREMENTAL]]
[TO[db.]name] [(columns)] [ENGINE = engine]
[EMPTY]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

em que `interval` é uma sequência de intervalos simples:

```sql theme={null}
number SECOND|MINUTE|HOUR|DAY|WEEK|MONTH|YEAR
```

A cláusula `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](#refresh-dependencies) abaixo.

Executa periodicamente a consulta correspondente e armazena o resultado em uma tabela.

* Se `APPEND` for especificado, cada atualização insere linhas na tabela sem excluir as já existentes. A inserção não é atômica, assim como em uma consulta `INSERT INTO ... SELECT` comum.
* Se `APPEND INCREMENTAL` for 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.

Diferenças em relação às visões materializadas comuns, não atualizáveis:

* 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 origem `MergeTree` simples com `enable_block_number_column = 1` e `enable_block_offset_column = 1` e rejeita `JOIN`, `UNION`, subconsultas, VIEWs e funções de tabela.

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

### Programação de atualização

Exemplos de programação de atualização:

```sql theme={null}
REFRESH EVERY 1 DAY -- every day, at midnight (UTC)
REFRESH EVERY 1 MONTH -- on 1st day of every month, at midnight
REFRESH EVERY 1 MONTH OFFSET 5 DAY 2 HOUR -- on 6th day of every month, at 2:00 am
REFRESH EVERY 2 WEEK OFFSET 5 DAY 15 HOUR 10 MINUTE -- every other Saturday, at 3:10 pm
REFRESH EVERY 30 MINUTE -- at 00:00, 00:30, 01:00, 01:30, etc
REFRESH AFTER 30 MINUTE -- 30 minutes after the previous refresh completes, no alignment with time of day
-- REFRESH AFTER 1 HOUR OFFSET 1 MINUTE -- syntax error, OFFSET is not allowed with AFTER
REFRESH EVERY 1 WEEK 2 DAYS -- every 9 days, not on any particular day of the week or month;
                            -- specifically, when day number (since 1969-12-29) is divisible by 9
REFRESH EVERY 5 MONTHS -- every 5 months, different months each year (as 12 is not divisible by 5);
                       -- specifically, when month number (since 1970-01) is divisible by 5
```

`RANDOMIZE FOR` ajusta aleatoriamente o momento de cada atualização, por exemplo:

```sql theme={null}
REFRESH EVERY 1 DAY OFFSET 2 HOUR RANDOMIZE FOR 1 HOUR -- every day at random time between 01:30 and 02:30
```

No máximo, uma atualização pode estar em execução por vez para uma determinada VIEW. Por exemplo, se uma VIEW com `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](/pt-BR/reference/engines/database-engines/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](/pt-BR/reference/engines/table-engines/mergetree-family/replication) é necessário para que todas as réplicas vejam os dados produzidos pela atualização.

No modo `APPEND`, 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](/pt-BR/reference/settings/server-settings/settings/default-replica#default_replica_path).

### Dependências de atualização

`DEPENDS ON` sincroniza as atualizações de diferentes tabelas:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH EVERY 1 HOUR DEPENDS ON dependency [...]
```

A atualização da VIEW dependente só começará depois que todas as VIEWs das quais ela depende forem atualizadas.

Para atualizar imediatamente após a atualização de outra VIEW:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH AFTER 0 SECOND DEPENDS ON dependency [...]
```

Ou, equivalentemente:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH DEPENDS ON dependency [...]
```

<Note>
  `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](#changing-refresh-parameters).
</Note>

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

```text theme={null}
           10:00            11:00            12:00
           │                │                │
  X:        [run]┐           [run]┐           [run]┐
                 │                │                │
  Y:             └►[run]          └►[run]          └►[run]
```

Tanto a dependência quanto o dependente podem, independentemente, pular intervalos de tempo se as atualizações levarem mais tempo do que o período de atualização. Não há garantia de que o dependente seja atualizado exatamente uma vez para cada atualização da dependência.

```text theme={null}
           10:00          11:00          12:00          13:00
           │              │              │              |
  X:        [run]┐         [run]┐         [run]┐         [run]┐
                 │              └────┐    (Y skips 12:00)     └───┐
  Y:             └►[10:00 ru------un]└►[11:00 ru---------------un]└►[13:00 run]
```

#### Usando DEPENDS ON para processamento em lote de streams

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

1. X pega um lote de linhas de algum stream e as coloca em uma tabela.
2. Em seguida, Y e Z leem dessa tabela, fazem agregações diferentes e acrescentam os resultados a outras tabelas.
3. Depois que o lote for totalmente processado, X pega o próximo lote, e o ciclo se repete.

```text theme={null}
            source
               │
               ▼
          ┌─────────┐
     ┌───►│    X    │◄───┐
     │    └──┬───┬──┘    │
  DEPENDS    │   │    DEPENDS
    ON       ▼   ▼      ON
     │      ┌─┐ ┌─┐      │
     └──────┤Y│ │Z├──────┘
            └─┘ └─┘
```

Exemplo completo:

```sql theme={null}
CREATE TABLE current_batch (t UInt64, v Int64) ENGINE ReplicatedMergeTree ORDER BY t;
CREATE TABLE batch_log (max_t UInt64, n Int64, v_sum Int64, processed_at DateTime64) ENGINE ReplicatedMergeTree ORDER BY max_t;
CREATE TABLE stats (h UInt64, n UInt64) ENGINE ReplicatedSummingMergeTree ORDER BY h;

-- (system.numbers stands in for a data source with monotonically increasing timestamps or sequence numbers)
CREATE MATERIALIZED VIEW current_batch_v REFRESH EVERY 10 SECOND DEPENDS ON batch_log_v, stats_v TO current_batch AS SELECT number as t, number * 10 as v FROM system.numbers WHERE number > (SELECT max(max_t) FROM batch_log) LIMIT 100;

CREATE MATERIALIZED VIEW batch_log_v REFRESH DEPENDS ON current_batch_v APPEND TO batch_log AS SELECT max(t) as max_t, count() as n, sum(v) as v_sum, now64() as processed_at FROM current_batch;

CREATE MATERIALIZED VIEW stats_v REFRESH DEPENDS ON current_batch_v APPEND TO stats AS SELECT cityHash64(v) % 20 as h, count() as n FROM current_batch GROUP BY h;

-- Must trigger initial refresh manually.
SYSTEM REFRESH VIEW current_batch_v;
```

Encadeamentos mais longos também funcionam.

Isso só funciona bem quando a coordenação da atualização está habilitada, ou seja, quando as VIEWs estão em um banco de dados Replicated ou Shared. Sem coordenação, a reinicialização do servidor interrompe o ciclo, exigindo um `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, se `refresh_retries` nã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](/pt-BR/reference/engines/database-engines/replicated) com `APPEND`, 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 com [`ALTER TABLE ... MODIFY REFRESH`](/pt-BR/reference/statements/alter/view#alter-table--modify-refresh-statement):

```sql theme={null}
ALTER TABLE [db.]name MODIFY REFRESH EVERY|AFTER ... [RANDOMIZE FOR ...] [DEPENDS ON ...] [SETTINGS ...]
```

O agendamento (`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).

<Note>
  * Para alterar apenas as configurações de atualização (por exemplo, `refresh_retries`), repita o agendamento atual:

    ```sql theme={null}
    ALTER TABLE rmv MODIFY REFRESH EVERY 1 HOUR SETTINGS refresh_retries = 5;
    ```

  * `ALTER TABLE ... MODIFY SETTING refresh_retries = ...` não tem suporte em visões materializadas; é preciso usar `MODIFY REFRESH`.

  * Não há suporte para alterar o modo de atualização: `APPEND` e `INCREMENTAL` não podem ser adicionados nem removidos.

  * A configuração `all_replicas` não pode ser alterada após a criação.
</Note>

Exemplos:

```sql theme={null}
-- Change the schedule, drop existing settings and dependencies.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE;

-- Change the schedule and tune retry behavior.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE
SETTINGS refresh_retries = 5,
         refresh_retry_initial_backoff_ms = 500,
         refresh_retry_max_backoff_ms = 60000;

-- Keep the dependency while changing the period.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR DEPENDS ON other_rmv;

-- Drop the dependency by omitting `DEPENDS ON`.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR;
```

### Outras operações

O status de todas as visões materializadas atualizáveis está disponível na tabela [`system.view_refreshes`](/pt-BR/reference/system-tables/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`](/pt-BR/reference/statements/system#managing-refreshable-materialized-views).

Para aguardar a conclusão de uma atualização, use [`SYSTEM WAIT VIEW`](/pt-BR/reference/statements/system#wait-view). Isso é útil, em particular, para aguardar a atualização inicial após criar uma view.

<Note>
  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==](https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==)
</Note>

## Conteúdo relacionado

* Blog: [Trabalhando com dados de séries temporais no ClickHouse](https://clickhouse.com/blog/working-with-time-series-data-and-functions-ClickHouse)
* Blog: [Criando uma solução de observabilidade com ClickHouse - Parte 2 - Traces](https://clickhouse.com/blog/storing-traces-and-spans-open-telemetry-in-clickhouse)

## 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 armazenamento `View`). Ela não persiste dados e não aceita `INSERT`.

* **Cláusula de engine**
  Você **não** precisa especificar `ENGINE`; se ele for informado como `ENGINE = 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 por `CREATE VIEW`.

* **SHOW CREATE**
  Use `SHOW CREATE TEMPORARY VIEW view_name;` para exibir o DDL de uma view temporária.

### Sintaxe

```sql theme={null}
CREATE TEMPORARY VIEW [IF NOT EXISTS] view_name AS <select_query>
```

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

```sql theme={null}
CREATE TEMPORARY TABLE t_src (id UInt32, val String);
INSERT INTO t_src VALUES (1, 'a'), (2, 'b');

CREATE TEMPORARY VIEW tview AS
SELECT id, upper(val) AS u
FROM t_src
WHERE id <= 2;

SELECT * FROM tview ORDER BY id;
```

Exiba a DDL:

```sql theme={null}
SHOW CREATE TEMPORARY VIEW tview;
```

Removê-la:

```sql theme={null}
DROP TEMPORARY VIEW IF EXISTS tview;  -- views temporárias são removidas com a sintaxe TEMPORARY TABLE
```

### Não permitidos / limitações

* `CREATE OR REPLACE TEMPORARY VIEW ...` → **não permitido** (use `DROP` + `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.

#### Exemplo

```sql theme={null}
-- A session-scoped, in-memory table
CREATE TEMPORARY TABLE temp_ids (id UInt64) ENGINE = Memory;

INSERT INTO temp_ids VALUES (1), (5), (42);

-- A session-scoped view over the temp table (purely logical)
CREATE TEMPORARY VIEW v_ids AS
SELECT id FROM temp_ids;

-- Replace 'test' with your cluster name.
-- GLOBAL JOIN forces ClickHouse to *ship* the small join-side (temp_ids via v_ids)
-- to every remote server that executes the left side.
SELECT count()
FROM cluster('test', system.numbers) AS n
GLOBAL ANY INNER JOIN v_ids USING (id)
WHERE n.number < 100;

```
