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

> Herda de MergeTree, mas adiciona lógica para colapsar linhas durante o processo de mesclagem.

# motor de tabela CollapsingMergeTree

<div id="description">
  ## Descrição
</div>

O motor `CollapsingMergeTree` herda de [MergeTree](/docs/pt-BR/reference/engines/table-engines/mergetree-family/mergetree)
e adiciona lógica para colapsar linhas durante o processo de mesclagem.
O motor de tabela `CollapsingMergeTree` exclui (colapsa) de forma assíncrona
pares de linhas se todos os campos da chave de ordenação (`ORDER BY`) forem equivalentes, exceto o campo especial `Sign`,
que pode ter valor `1` ou `-1`.
As linhas sem um par com valor oposto de `Sign` são mantidas.

Para mais detalhes, consulte a seção [Collapsing](#table_engine-collapsingmergetree-collapsing) deste documento.

<Note>
  Este motor pode reduzir significativamente o volume de armazenamento,
  aumentando, consequentemente, a eficiência das consultas `SELECT`.
</Note>

<div id="parameters">
  ## Parâmetros
</div>

Todos os parâmetros deste motor de tabela, com exceção do parâmetro `Sign`,
têm o mesmo significado que em [`MergeTree`](/docs/pt-BR/reference/engines/table-engines/mergetree-family/mergetree).

* `Sign` — O nome dado a uma coluna que indica o tipo de linha, em que `1` é uma linha de "estado" e `-1` é uma linha de "cancelamento". Tipo: [Int8](/docs/pt-BR/reference/data-types/int-uint).

<div id="creating-a-table">
  ## Criando uma tabela
</div>

```sql theme={null}
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
)
ENGINE = CollapsingMergeTree(Sign)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
```

<details markdown="1">
  <summary>Método obsoleto para criar uma tabela</summary>

  <Note>
    O método abaixo não é recomendado para uso em novos projetos.
    Recomendamos, se possível, atualizar projetos antigos para usar o novo método.
  </Note>

  ```sql theme={null}
  CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
  (
      name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
      name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
      ...
  )
  ENGINE [=] CollapsingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, Sign)
  ```

  `Sign` — O nome dado a uma coluna que indica o tipo de linha, em que `1` é uma linha de "estado" e `-1` é uma linha de "cancelamento". [Int8](/docs/pt-BR/reference/data-types/int-uint).
</details>

* Para uma descrição dos parâmetros de consulta, consulte a [descrição da consulta](/docs/pt-BR/reference/statements/create/table).
* Ao criar uma tabela `CollapsingMergeTree`, são exigidas as mesmas [cláusulas da consulta](/docs/pt-BR/reference/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-creating-a-table) usadas na criação de uma tabela `MergeTree`.

<div id="table_engine-collapsingmergetree-collapsing">
  ## Collapsing
</div>

<div id="data">
  ### Dados
</div>

Considere a situação em que você precisa salvar dados que mudam continuamente de um determinado objeto.
Pode parecer lógico ter uma linha por objeto e atualizá-la sempre que algo mudar,
porém, operações de atualização são caras e lentas para o SGBD, porque exigem a regravação dos dados no armazenamento.
Se precisarmos gravar dados rapidamente, realizar um grande número de atualizações não é uma abordagem aceitável,
mas sempre podemos gravar sequencialmente as alterações de um objeto.
Para isso, usamos a coluna especial `Sign`.

* Se `Sign` = `1`, isso significa que a linha é uma linha de "estado": *uma linha que contém campos que representam o estado válido atual*.
* Se `Sign` = `-1`, isso significa que a linha é uma linha de "cancelamento": *uma linha usada para cancelar o estado de um objeto com os mesmos atributos*.

Por exemplo, queremos calcular quantas páginas os usuários visitaram em um site e por quanto tempo permaneceram nelas.
Em um determinado momento, gravamos a seguinte linha com o estado da atividade do usuário:

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

Em um momento posterior, registramos a mudança na atividade do usuário e a gravamos nas duas linhas a seguir:

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

A primeira linha cancela o estado anterior do objeto (neste caso, representando um usuário).
Ela deve copiar todos os campos da chave de ordenação da linha "cancelada", exceto `Sign`.
A segunda linha acima contém o estado atual.

Como precisamos apenas do estado mais recente da atividade do usuário, a linha original de "estado" e a linha de "cancelamento"
que inserimos podem ser excluídas, como mostrado abaixo, colapsando o estado inválido (antigo) de um objeto:

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │ -- old "state" row can be deleted
│ 4324182021466249494 │         5 │      146 │   -1 │ -- "cancel" row can be deleted
│ 4324182021466249494 │         6 │      185 │    1 │ -- new "state" row remains
└─────────────────────┴───────────┴──────────┴──────┘
```

`CollapsingMergeTree` realiza precisamente esse comportamento de *colapso* enquanto ocorre a mesclagem das partes de dados.

<Note>
  O motivo pelo qual duas linhas são necessárias para cada alteração
  é discutido em mais detalhes no parágrafo [Algoritmo](#table_engine-collapsingmergetree-collapsing-algorithm).
</Note>

**As particularidades dessa abordagem**

1. O programa que escreve os dados deve se lembrar do estado de um objeto para poder cancelá-lo. A linha de "cancelamento" deve conter cópias dos campos da chave de ordenação do "estado" e o `Sign` oposto. Isso aumenta o tamanho inicial do armazenamento, mas permite gravar os dados rapidamente.
2. Arrays longos e que continuam crescendo nas colunas reduzem a eficiência do motor devido ao aumento da carga de gravação. Quanto mais simples forem os dados, maior será a eficiência.
3. Os resultados de `SELECT` dependem fortemente da consistência do histórico de alterações do objeto. Seja preciso ao preparar os dados para inserção. Dados inconsistentes podem gerar resultados imprevisíveis. Por exemplo, valores negativos para métricas não negativas, como profundidade de sessão.

<div id="table_engine-collapsingmergetree-collapsing-algorithm">
  ### Algoritmo
</div>

Quando o ClickHouse mescla [partes](/docs/pt-BR/concepts/core-concepts/glossary#parts),
cada grupo de linhas consecutivas com a mesma chave de ordenação (`ORDER BY`) é reduzido a no máximo duas linhas:
a linha de "estado" com `Sign` = `1` e a linha de "cancelamento" com `Sign` = `-1`.
Em outras palavras, no ClickHouse as entradas são colapsadas.

Para cada parte de dados resultante, o ClickHouse salva:

|    |                                                                                                                                                                              |
| -- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1. | A primeira linha de "cancelamento" e a última linha de "estado", se o número de linhas de "estado" e de "cancelamento" for igual e a última linha for uma linha de "estado". |
| 2. | A última linha de "estado", se houver mais linhas de "estado" do que de "cancelamento".                                                                                      |
| 3. | A primeira linha de "cancelamento", se houver mais linhas de "cancelamento" do que de "estado".                                                                              |
| 4. | Nenhuma linha, em todos os outros casos.                                                                                                                                     |

Além disso, quando há pelo menos duas linhas de "estado" a mais do que linhas de "cancelamento"
ou pelo menos duas linhas de "cancelamento" a mais do que linhas de "estado", a mesclagem continua.
No entanto, o ClickHouse trata essa situação como um erro lógico e a registra no log do servidor.
Esse erro pode ocorrer se os mesmos dados forem inseridos mais de uma vez.
Assim, o colapsamento não deve alterar os resultados do cálculo de estatísticas.
As alterações são gradualmente colapsadas para que, no fim, reste apenas o último estado de quase todos os objetos.

A coluna `Sign` é necessária porque o algoritmo de mesclagem não garante
que todas as linhas com a mesma chave de ordenação estarão na mesma parte de dados resultante, nem mesmo no mesmo servidor físico.
O ClickHouse processa consultas `SELECT` com múltiplas threads e não pode prever a ordem das linhas no resultado.

A agregação é necessária quando se precisa obter dados totalmente "colapsados" da tabela `CollapsingMergeTree`.
Para concluir o colapsamento, escreva uma consulta com a cláusula `GROUP BY` e funções de agregação que levem o sinal em conta.
Por exemplo, para calcular a quantidade, use `sum(Sign)` em vez de `count()`.
Para calcular a soma de alguma coisa, use `sum(Sign * x)` junto com `HAVING sum(Sign) > 0` em vez de `sum(x)`
como no [exemplo](#example-of-use) abaixo.

As funções de agregação `count`, `sum` e `avg` podem ser calculadas dessa forma.
A função de agregação `uniq` pode ser calculada se um objeto tiver pelo menos um estado não colapsado.
As funções de agregação `min` e `max` não podem ser calculadas
porque o `CollapsingMergeTree` não salva o histórico dos estados colapsados.

<Note>
  Se você precisar extrair dados sem agregação
  (por exemplo, para verificar se há linhas cujos valores mais recentes correspondem a determinadas condições),
  pode usar o modificador [`FINAL`](/docs/pt-BR/reference/statements/select/from#final-modifier) para a cláusula `FROM`. Ele mesclará os dados antes de retornar o resultado.
  Para CollapsingMergeTree, apenas a linha de estado mais recente de cada chave é retornada.
</Note>

<div id="examples">
  ## Exemplos
</div>

<div id="example-of-use">
  ### Exemplo de uso
</div>

Considere os dados de exemplo a seguir:

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
│ 4324182021466249494 │         5 │      146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

Vamos criar a tabela `UAct` usando o `CollapsingMergeTree`:

```sql theme={null}
CREATE TABLE UAct
(
    UserID UInt64,
    PageViews UInt8,
    Duration UInt8,
    Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID
```

Em seguida, vamos inserir alguns dados:

```sql theme={null}
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1)
```

```sql theme={null}
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1),(4324182021466249494, 6, 185, 1)
```

Usamos duas consultas `INSERT` para criar duas partes de dados diferentes.

<Note>
  Se inserirmos os dados com uma única consulta, o ClickHouse criará apenas uma parte de dados e nunca fará nenhuma mesclagem.
</Note>

Podemos selecionar os dados usando:

```sql theme={null}
SELECT * FROM UAct
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

Vamos dar uma olhada nos dados retornados acima e ver se houve colapso...
Com duas consultas `INSERT`, criamos duas partes de dados.
A consulta `SELECT` foi executada em dois threads, e obtivemos uma ordem aleatória das linhas.
No entanto, o colapso **não ocorreu** porque ainda não havia acontecido nenhuma mesclagem das partes de dados
e o ClickHouse faz mesclagem das partes de dados em segundo plano, em um momento desconhecido que não podemos prever.

Portanto, precisamos de uma agregação,
que realizamos com a função de agregação [`sum`](/docs/pt-BR/reference/functions/aggregate-functions/sum)
e a cláusula [`HAVING`](/docs/pt-BR/reference/statements/select/having):

```sql theme={null}
SELECT
    UserID,
    sum(PageViews * Sign) AS PageViews,
    sum(Duration * Sign) AS Duration
FROM UAct
GROUP BY UserID
HAVING sum(Sign) > 0
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 4324182021466249494 │         6 │      185 │
└─────────────────────┴───────────┴──────────┘
```

Se não precisarmos de agregação e quisermos forçar a operação de colapso, também podemos usar o modificador `FINAL` na cláusula `FROM`.

```sql theme={null}
SELECT * FROM UAct FINAL
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

<Note>
  Essa forma de selecionar os dados é menos eficiente e não é recomendada para grandes volumes de dados lidos (milhões de linhas).
</Note>

<div id="example-of-another-approach">
  ### Exemplo de outra abordagem
</div>

A ideia por trás dessa abordagem é que as mesclagens levem em conta apenas os campos-chave.
Na linha "cancelamento", portanto, podemos especificar valores negativos
que compensam a versão anterior da linha ao somar, sem usar a coluna `Sign`.

Para este exemplo, usaremos os dados de exemplo abaixo:

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         5 │      146 │    1 │
│ 4324182021466249494 │        -5 │     -146 │   -1 │
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

Para essa abordagem, é necessário alterar os tipos de dados de `PageViews` e `Duration` para armazenar valores negativos.
Por isso, alteramos os tipos dessas colunas de `UInt8` para `Int16` ao criar nossa tabela `UAct` usando a
`collapsingMergeTree`:

```sql theme={null}
CREATE TABLE UAct
(
    UserID UInt64,
    PageViews Int16,
    Duration Int16,
    Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID
```

Vamos testar a abordagem inserindo dados na nossa tabela.

No entanto, para exemplos ou tabelas pequenas, isso é aceitável:

```sql theme={null}
INSERT INTO UAct VALUES(4324182021466249494,  5,  146,  1);
INSERT INTO UAct VALUES(4324182021466249494, -5, -146, -1);
INSERT INTO UAct VALUES(4324182021466249494,  6,  185,  1);

SELECT * FROM UAct FINAL;
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```

```sql theme={null}
SELECT
    UserID,
    sum(PageViews) AS PageViews,
    sum(Duration) AS Duration
FROM UAct
GROUP BY UserID
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 4324182021466249494 │         6 │      185 │
└─────────────────────┴───────────┴──────────┘
```

```sql theme={null}
SELECT COUNT() FROM UAct
```

```text theme={null}
┌─count()─┐
│       3 │
└─────────┘
```

```sql theme={null}
OPTIMIZE TABLE UAct FINAL;

SELECT * FROM UAct
```

```text theme={null}
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │         6 │      185 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘
```
