Este motor:
- Permite escribir rápidamente estados de objetos que cambian continuamente.
- Elimina en segundo plano estados antiguos de los objetos. Esto reduce significativamente el volumen de almacenamiento.
Consulte la sección Collapsing para obtener más información.
El motor hereda de MergeTree y añade la lógica de colapso de filas al algoritmo de fusión de partes de datos. VersionedCollapsingMergeTree cumple la misma función que CollapsingMergeTree, pero utiliza un algoritmo de colapso diferente que permite insertar los datos en cualquier orden con varios hilos. En particular, la columna Version ayuda a colapsar correctamente las filas incluso si se insertan en un orden incorrecto. En cambio, CollapsingMergeTree solo permite una inserción estrictamente consecutiva.
Crear una tabla
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = VersionedCollapsingMergeTree(sign, version)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]Para ver una descripción de los parámetros de consulta, consulte la descripción de la consulta.
Parámetros del motor
VersionedCollapsingMergeTree(sign, version)| Parámetro | Descripción | Tipo |
|---|---|---|
sign |
Nombre de la columna que indica el tipo de fila: 1 es una fila de "estado", -1 es una fila de "cancelación". |
Int8 |
version |
Nombre de la columna con la versión del estado del objeto. | Int*, UInt*, Date, Date32, DateTime o DateTime64 |
Cláusulas de la consulta
Al crear una tabla VersionedCollapsingMergeTree, se requieren las mismas cláusulas que al crear una tabla MergeTree.
Método obsoleto para crear una tabla
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE [=] VersionedCollapsingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, sign, version)Todos los parámetros, excepto sign y version, tienen el mismo significado que en MergeTree.
-
sign— Nombre de la columna con el tipo de fila:1es una fila "estado" y-1es una fila "cancelación".Tipo de datos de la columna:
Int8. -
version— Nombre de la columna con la versión del estado del objeto.El tipo de datos de la columna debe ser
UInt*.
Collapsing
Datos
Considere una situación en la que necesita guardar datos que cambian continuamente de un objeto. Es razonable tener una fila por objeto y actualizarla cada vez que haya cambios. Sin embargo, la operación de actualización es costosa y lenta para un SGBD porque requiere reescribir los datos en el almacenamiento. La actualización no es aceptable si necesita escribir datos rápidamente, pero puede escribir los cambios de un objeto de forma secuencial, como se muestra a continuación.
Use la columna Sign al escribir la fila. Si Sign = 1, significa que la fila representa un estado de un objeto (llamémosla la fila de "estado"). Si Sign = -1, indica la anulación del estado de un objeto con los mismos atributos (llamémosla la fila de "cancelación"). Use también la columna Version, que debe identificar cada estado de un objeto con un número distinto.
Por ejemplo, queremos calcular cuántas páginas visitaron los usuarios en un sitio y cuánto tiempo permanecieron allí. En algún momento escribimos la siguiente fila con el estado de la actividad del usuario:
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │ 1 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘Más adelante, registramos el cambio en la actividad del usuario y lo escribimos en las dos filas siguientes.
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ -1 │ 1 |
│ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘La primera fila cancela el estado anterior del objeto (usuario). Debe copiar todos los campos del estado cancelado excepto Sign.
La segunda fila contiene el estado actual.
Como solo necesitamos el último estado de la actividad del usuario, las filas
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │ 1 |
│ 4324182021466249494 │ 5 │ 146 │ -1 │ 1 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘puede eliminarse, colapsando el estado no válido (antiguo) del objeto. VersionedCollapsingMergeTree lo hace durante la fusión de las partes de datos.
Para averiguar por qué necesitamos dos filas para cada cambio, consulta Algorithm.
Notas sobre el uso
- El programa que escribe los datos debe recordar el estado de un objeto para poder cancelarlo. La cadena "Cancel" debe contener copias de los campos de la clave primaria, la versión de la cadena "estado" y el
Signopuesto. Esto aumenta el tamaño inicial del almacenamiento, pero permite escribir los datos con rapidez. - Los arrays largos y en crecimiento en las columnas reducen la eficiencia del motor debido a la carga de escritura. Cuanto más sencillos sean los datos, mayor será la eficiencia.
- Los resultados de
SELECTdependen en gran medida de la coherencia del historial de cambios de los objetos. Sé preciso al preparar los datos para insertarlos. Los datos incoherentes pueden producir resultados impredecibles, como valores negativos para métricas no negativas, como la profundidad de la sesión.
Algoritmo
Cuando ClickHouse fusiona partes de datos, elimina cada par de filas que tienen la misma clave primaria y la misma versión, pero distinto Sign. El orden de las filas no importa.
Cuando ClickHouse inserta datos, ordena las filas por la clave primaria. Si la columna Version no forma parte de la clave primaria, ClickHouse la añade implícitamente al final de esta y la usa para la ordenación.
Selección de datos
ClickHouse no garantiza que todas las filas con la misma clave primaria estén en la misma parte de datos resultante ni siquiera en el mismo servidor físico. Esto es así tanto al escribir los datos como durante la posterior fusión de las partes de datos. Además, ClickHouse procesa las consultas SELECT con varios hilos y no puede predecir el orden de las filas en el resultado. Esto significa que se requiere agregación si se necesita obtener datos completamente "colapsados" de una tabla VersionedCollapsingMergeTree.
Para finalizar el colapso, escriba una consulta con una cláusula GROUP BY y funciones de agregado 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) en lugar de sum(x), y añada HAVING sum(Sign) > 0.
Los agregados count, sum y avg pueden calcularse de esta manera. El agregado uniq puede calcularse si un objeto tiene al menos un estado no colapsado. Los agregados min y max no pueden calcularse porque VersionedCollapsingMergeTree no guarda el historial de valores de los estados colapsados.
Si necesita extraer los datos con "colapso" pero sin agregación (por ejemplo, para comprobar si hay filas cuyos valores más recientes coinciden con ciertas condiciones), puede usar el modificador FINAL para la cláusula FROM. Este enfoque es ineficiente y no debe usarse con tablas grandes.
Ejemplo de uso
Datos de ejemplo:
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │ 1 |
│ 4324182021466249494 │ 5 │ 146 │ -1 │ 1 |
│ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘Crear la tabla:
CREATE TABLE UAct
(
UserID UInt64,
PageViews UInt8,
Duration UInt8,
Sign Int8,
Version UInt8
)
ENGINE = VersionedCollapsingMergeTree(Sign, Version)
ORDER BY UserIDInserción de datos:
INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1, 1)INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1, 1),(4324182021466249494, 6, 185, 1, 2)Usamos dos consultas INSERT para crear dos partes de datos distintas. Si insertamos los datos con una sola consulta, ClickHouse crea una sola parte de datos y nunca realizará ningún merge.
Obtención de los datos:
SELECT * FROM UAct┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 5 │ 146 │ -1 │ 1 │
│ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘¿Qué vemos aquí y dónde están las partes colapsadas?
Creamos dos partes de datos mediante dos consultas INSERT. La consulta SELECT se ejecutó en dos hilos y el resultado muestra las filas en un orden aleatorio.
El colapso no ocurrió porque las partes de datos aún no se han fusionado. ClickHouse fusiona las partes de datos en algún momento desconocido que no podemos predecir.
Por eso necesitamos agregación:
SELECT
UserID,
sum(PageViews * Sign) AS PageViews,
sum(Duration * Sign) AS Duration,
Version
FROM UAct
GROUP BY UserID, Version
HAVING sum(Sign) > 0┌──────────────UserID─┬─PageViews─┬─Duration─┬─Version─┐
│ 4324182021466249494 │ 6 │ 185 │ 2 │
└─────────────────────┴───────────┴──────────┴─────────┘Si no necesitamos agregación y queremos forzar el colapso, podemos usar el modificador FINAL en la cláusula FROM.
SELECT * FROM UAct FINAL┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘Esta es una forma muy ineficiente de seleccionar datos. No la utilice para tablas grandes.