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

> Hereda de MergeTree, pero añade lógica para colapsar filas durante el proceso de fusión.

# motor de tabla de CollapsingMergeTree

<div id="description">
  ## Descripción
</div>

El motor `CollapsingMergeTree` hereda de [MergeTree](/docs/es/reference/engines/table-engines/mergetree-family/mergetree)
y añade lógica para colapsar filas durante el proceso de fusión.
El motor de tabla `CollapsingMergeTree` elimina (colapsa) de forma asíncrona
pares de filas si todos los campos de la clave de ordenación (`ORDER BY`) son equivalentes, excepto el campo especial `Sign`,
que puede tener los valores `1` o `-1`.
Las filas que no tienen una pareja con el valor opuesto de `Sign` se conservan.

Para obtener más información, consulte la sección [colapsado](#table_engine-collapsingmergetree-collapsing) de este documento.

<Note>
  Este motor puede reducir significativamente el volumen de almacenamiento,
  lo que, en consecuencia, aumenta la eficiencia de las consultas `SELECT`.
</Note>

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

Todos los parámetros de este motor de tabla, salvo el parámetro `Sign`,
tienen el mismo significado que en [`MergeTree`](/docs/es/reference/engines/table-engines/mergetree-family/mergetree).

* `Sign` — El nombre de una columna con el tipo de fila, donde `1` es una fila de estado y `-1` es una fila de cancelación. Tipo: [Int8](/docs/es/reference/data-types/int-uint).

<div id="creating-a-table">
  ## Crear una tabla
</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 crear una tabla</summary>

  <Note>
    El método que se muestra a continuación no se recomienda para proyectos nuevos.
    Si es posible, recomendamos actualizar los proyectos antiguos para que usen el nuevo 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` — El nombre que se da a una columna que indica el tipo de fila: `1` es una fila de "estado" y `-1` es una fila de "cancelación". [Int8](/docs/es/reference/data-types/int-uint).
</details>

* Para ver una descripción de los parámetros de consulta, consulte la [descripción de la consulta](/docs/es/reference/statements/create/table).
* Al crear una tabla `CollapsingMergeTree`, se requieren las mismas [cláusulas de consulta](/docs/es/reference/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-creating-a-table) que al crear una tabla `MergeTree`.

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

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

Considera la situación en la que necesitas guardar datos que cambian continuamente para un objeto determinado.
Puede parecer lógico tener una fila por objeto y actualizarla cada vez que cambie algo;
sin embargo, las operaciones de actualización son costosas y lentas para el DBMS porque requieren reescribir los datos en el almacenamiento.
Si necesitamos escribir datos rápidamente, realizar un gran número de actualizaciones no es un enfoque aceptable,
pero siempre podemos escribir los cambios de un objeto de forma secuencial.
Para ello, utilizamos la columna especial `Sign`.

* Si `Sign` = `1`, significa que la fila es una fila de "estado": *una fila que contiene campos que representan un estado válido actual*.
* Si `Sign` = `-1`, significa que la fila es una fila de "cancelación": *una fila utilizada para cancelar el estado de un objeto con los mismos atributos*.

Por ejemplo, queremos calcular cuántas páginas visitaron los usuarios en un sitio web y durante cuánto tiempo.
En un momento dado, escribimos la siguiente fila con el estado de la actividad del usuario:

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

Más adelante, registramos el cambio en la actividad del usuario y lo escribimos con las dos filas siguientes:

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

La primera fila cancela el estado anterior del objeto (que en este caso representa a un usuario).
Debe copiar todos los campos de la clave de ordenación de la fila "cancelada", excepto `Sign`.
La segunda fila anterior contiene el estado actual.

Como solo necesitamos el último estado de la actividad del usuario, la fila original de "estado" y la fila de "cancelación"
que insertamos pueden eliminarse, como se muestra a continuación, colapsando el estado no válido (antiguo) de un 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` lleva a cabo precisamente este comportamiento de *collapsing* durante la fusión de las partes de datos.

<Note>
  La razón por la que se necesitan dos filas para cada cambio
  se explica con más detalle en el apartado [Algoritmo](#table_engine-collapsingmergetree-collapsing-algorithm).
</Note>

**Las particularidades de este enfoque**

1. El programa que escribe los datos debe recordar el estado de un objeto para poder cancelarlo. La fila de "cancelación" debe contener copias de los campos de la clave de ordenación del "estado" y el `Sign` opuesto. Esto aumenta el tamaño inicial del almacenamiento, pero permite escribir los datos rápidamente.
2. Los arrays largos y en crecimiento en las columnas reducen la eficiencia del engine debido al aumento de la carga de escritura. Cuanto más sencillos sean los datos, mayor será la eficiencia.
3. Los resultados de `SELECT` dependen en gran medida de la consistencia del historial de cambios del objeto. Sea preciso al preparar los datos para insertarlos. Los datos inconsistentes pueden producir resultados impredecibles. Por ejemplo, valores negativos para métricas no negativas, como la profundidad de la sesión.

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

Cuando ClickHouse fusiona [partes](/docs/es/concepts/core-concepts/glossary#parts) de datos,
cada grupo de filas consecutivas con la misma clave de ordenación (`ORDER BY`) se reduce a no más de dos filas:
la fila de estado con `Sign` = `1` y la fila de cancelación con `Sign` = `-1`.
En otras palabras, en ClickHouse las entradas se colapsan.

Para cada parte de datos resultante, ClickHouse guarda:

|    |                                                                                                                                                              |
| -- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1. | La primera fila de cancelación y la última fila de estado, si el número de filas de estado y de cancelación coincide y la última fila es una fila de estado. |
| 2. | La última fila de estado, si hay más filas de estado que filas de cancelación.                                                                               |
| 3. | La primera fila de cancelación, si hay más filas de cancelación que filas de estado.                                                                         |
| 4. | Ninguna fila, en todos los demás casos.                                                                                                                      |

Además, cuando hay al menos dos filas de estado más que filas de cancelación
o al menos dos filas de cancelación más que filas de estado, la fusión continúa.
Sin embargo, ClickHouse considera esta situación un error lógico y lo registra en el registro del servidor.
Este error puede producirse si los mismos datos se insertan más de una vez.
Por lo tanto, el colapsado no debería cambiar los resultados del cálculo de estadísticas.
Los cambios se colapsan gradualmente, de modo que al final solo queda el último estado de casi todos los objetos.

La columna `Sign` es necesaria porque el algoritmo de fusión no garantiza
que todas las filas con la misma clave de ordenación estén en la misma parte de datos resultante ni siquiera en el mismo servidor físico.
ClickHouse procesa las consultas `SELECT` con múltiples hilos y no puede predecir el orden de las filas en el resultado.

La agregación es necesaria si se necesita obtener datos completamente "colapsados" de la tabla `CollapsingMergeTree`.
Para completar el colapsado, escriba una consulta con la cláusula `GROUP BY` y funciones de agregación que tengan en cuenta el signo.
Por ejemplo, para calcular la cantidad, use `sum(Sign)` en lugar de `count()`.
Para calcular la suma de algo, use `sum(Sign * x)` junto con `HAVING sum(Sign) > 0` en lugar de `sum(x)`,
como en el [ejemplo](#example-of-use) a continuación.

Las funciones de agregación `count`, `sum` y `avg` pueden calcularse de esta forma.
La función de agregación `uniq` puede calcularse si un objeto tiene al menos un estado no colapsado.
Las funciones de agregación `min` y `max` no pueden calcularse
porque `CollapsingMergeTree` no conserva el historial de los estados colapsados.

<Note>
  Si necesita extraer datos sin agregación
  (por ejemplo, para comprobar si existen filas cuyos valores más recientes coinciden con ciertas condiciones),
  puede usar el modificador [`FINAL`](/docs/es/reference/statements/select/from#final-modifier) para la cláusula `FROM`. Este fusionará los datos antes de devolver el resultado.
  Para CollapsingMergeTree, solo se devuelve la fila de estado más reciente para cada clave.
</Note>

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

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

Con los siguientes datos de ejemplo:

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

Vamos a crear una tabla `UAct` con `CollapsingMergeTree`:

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

A continuación, insertaremos algunos datos:

```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 dos consultas `INSERT` para crear dos partes de datos diferentes.

<Note>
  Si insertamos los datos con una sola consulta, ClickHouse crea solo una parte de datos y no realizará ninguna fusión.
</Note>

Podemos seleccionar los datos con:

```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 │
└─────────────────────┴───────────┴──────────┴──────┘
```

Veamos los datos devueltos arriba y comprobemos si se produjo el collapsing...
Con dos consultas `INSERT`, creamos dos partes de datos.
La consulta `SELECT` se ejecutó en dos hilos y obtuvimos un orden aleatorio de las filas.
Sin embargo, el collapsing **no se produjo** porque todavía no se había realizado ninguna fusión de las partes de datos,
y ClickHouse fusiona las partes de datos en segundo plano en un momento desconocido que no podemos predecir.

Por lo tanto, necesitamos una agregación,
que realizamos con la función de agregación [`sum`](/docs/es/reference/functions/aggregate-functions/sum)
y la cláusula [`HAVING`](/docs/es/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 │
└─────────────────────┴───────────┴──────────┘
```

Si no necesitamos agregación y queremos forzar el colapsado, también podemos usar el modificador `FINAL` en la cláusula `FROM`.

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

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

<Note>
  Esta forma de seleccionar los datos es menos eficiente y no se recomienda para grandes volúmenes de datos analizados (millones de filas).
</Note>

<div id="example-of-another-approach">
  ### Ejemplo de otro enfoque
</div>

La idea de este enfoque es que las fusiones solo tienen en cuenta los campos clave.
Por tanto, en la fila de "cancelación", podemos especificar valores negativos
que compensen la versión anterior de la fila al sumar, sin usar la columna `Sign`.

Para este ejemplo, utilizaremos los datos de muestra que aparecen a continuación:

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

Para este enfoque, es necesario cambiar los tipos de datos de `PageViews` y `Duration` para poder almacenar valores negativos.
Por lo tanto, cambiamos el tipo de estas columnas de `UInt8` a `Int16` cuando creamos nuestra tabla `UAct` con
`collapsingMergeTree`:

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

Probemos este enfoque insertando datos en nuestra tabla.

Sin embargo, en ejemplos o tablas pequeñas, es aceptable:

```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 │
└─────────────────────┴───────────┴──────────┴──────┘
```
