- En cualquier momento, tu tabla puede seguir teniendo duplicados (filas con la misma clave de ordenación)
- La eliminación real de las filas duplicadas se produce durante la fusión de partes
- Tus consultas deben contemplar la posibilidad de que existan duplicados
| ClickHouse ofrece formación gratuita sobre deduplicación y muchos otros temas. El módulo de formación Deleting and Updating Data es un buen punto de partida. |
Opciones de deduplicación
-
Motor de tabla
ReplacingMergeTree: con este motor de tabla, las filas duplicadas con la misma clave de ordenación se eliminan durante las fusiones.ReplacingMergeTreees una buena opción para emular el comportamiento de upsert (cuando quieres que las consultas devuelvan la última fila insertada). -
Colapso de filas: los motores de tabla
CollapsingMergeTreeyVersionedCollapsingMergeTreeusan una lógica en la que una fila existente se “cancela” y se inserta una fila nueva. Son más complejos de implementar queReplacingMergeTree, pero las consultas y agregaciones pueden ser más sencillas de escribir, sin tener que preocuparte de si los datos ya se han fusionado o no. Estos dos motores de tabla son útiles cuando necesitas actualizar datos con frecuencia.
Uso de ReplacingMergeTree para upserts
views que representa el número de veces que se ha visto un comentario. Supongamos que insertamos una nueva fila cuando se publica un artículo y que hacemos un upsert de una nueva fila una vez al día con el número total de visualizaciones si el valor aumenta:
views, inserta una nueva fila con la misma clave primaria (observa los nuevos valores de la columna views):
FINAL en la consulta SELECT, lo que da lugar a una fusión lógica del resultado de la consulta:
Usar
FINAL funciona bien si tienes pocos datos. Si estás trabajando con una gran cantidad de datos,
probablemente FINAL no sea la mejor opción. Veamos una alternativa mejor para
encontrar el valor más reciente de una columna.Evitar FINAL
views para ambas filas únicas:
FINAL).
FINAL, apliquemos cierta lógica de negocio: sabemos que la columna views siempre va en aumento, así que podemos seleccionar la fila con el valor máximo usando la función max después de agrupar por las columnas deseadas:
FINAL.
Nuestro Deleting and Updating Data training module amplía este ejemplo, incluido el uso de una columna version con ReplacingMergeTree.
Uso de CollapsingMergeTree para actualizar columnas con frecuencia
ALTER TABLE..UPDATE y, en su lugar, simplemente insertar los datos nuevos junto con los datos existentes. Podríamos añadir una columna que indique si los datos están obsoletos o son nuevos… y, de hecho, ya existe un motor de tabla que implementa este comportamiento de forma muy elegante, sobre todo porque elimina automáticamente los datos obsoletos. Veamos cómo funciona.
Supongamos que hacemos un seguimiento del número de visualizaciones de un comentario de Hacker News mediante un sistema externo y que, cada pocas horas, enviamos los datos a ClickHouse. Queremos que se eliminen las filas antiguas y que las filas nuevas representen el nuevo estado de cada comentario de Hacker News. Podemos usar un CollapsingMergeTree para implementar este comportamiento.
Definamos una tabla para almacenar el número de visualizaciones:
hackernews_views tiene una columna Int8 llamada sign, a la que se denomina columna de signo. El nombre de la columna de signo es arbitrario, pero el tipo de dato Int8 es obligatorio, y observe que el nombre de la columna se pasó al constructor de la tabla CollapsingMergeTree.
¿Qué es la columna de signo de una tabla CollapsingMergeTree? Representa el estado de la fila, y la columna de signo solo puede ser 1 o -1. Así funciona:
- Si dos filas tienen la misma clave primaria (o el criterio de ordenación, si es distinto de la clave primaria), pero distintos valores en la columna de signo, la última fila insertada con un +1 se convierte en la fila de estado y las demás filas se anulan entre sí
- Las filas que se anulan entre sí se eliminan durante las merges
- Las filas que no tienen un par correspondiente se conservan
hackernews_views. Como es la única fila para esta clave primaria, establecemos su estado en 1:
(123, 'ricardo'):
FINAL, se devuelve la fila correspondiente al estado actual:
FINAL en tablas grandes.
El valor que se pasa a la columna
views en nuestro ejemplo no es realmente necesario, ni tampoco tiene que coincidir con el valor actual de views de la fila anterior. De hecho, se puede cancelar una fila solo con la clave primaria y un -1:Actualizaciones en tiempo real desde varios hilos
CollapsingMergeTree, las filas se cancelan entre sí mediante una columna de signo, y el estado de una fila lo determina la última fila insertada. Pero esto puede ser problemático si insertas filas desde distintos hilos, ya que pueden insertarse fuera de orden. Usar la “última” fila no funciona en esta situación.
Aquí es donde VersionedCollapsingMergeTree resulta útil: colapsa filas igual que CollapsingMergeTree, pero en lugar de conservar la última fila insertada, conserva la fila con el valor más alto en una columna de versión que especifiques.
Veamos un ejemplo. Supongamos que queremos hacer un seguimiento del número de visualizaciones de nuestros comentarios de Hacker News y que los datos se actualizan con frecuencia. Queremos que los informes usen los valores más recientes sin forzar ni esperar fusiones. Empezamos con una tabla similar a CollapsedMergeTree, salvo que añadimos una columna para almacenar la versión del estado de la fila:
VersionsedCollapsingMergeTree como motor y especifica una columna de signo y una columna de versión. Así funciona la tabla:
- Elimina cada par de filas que tienen la misma clave primaria y la misma versión, pero distinto signo
- El orden en que se insertaron las filas no importa
- Tenga en cuenta que, si la columna de versión no forma parte de la clave primaria, ClickHouse la añade implícitamente a la clave primaria como el último campo
hackernews_views_vcmt:
VersionedCollapsingMergeTree resulta muy útil cuando se quiere implementar la deduplicación al insertar filas desde varios clientes y/o hilos.
¿Por qué mis filas no se deduplican?
INSERT. Por ejemplo, si estás insertando filas con la columna createdAt DateTime64(3) DEFAULT now(), se garantiza que tus filas serán únicas porque cada fila tendrá un valor por defecto único para la columna createdAt. El motor de tabla MergeTree / ReplicatedMergeTree no sabrá que debe deduplicar las filas, ya que cada fila insertada generará un checksum único.
En este caso, puedes especificar tu propio insert_deduplication_token para cada lote de filas a fin de garantizar que varias inserciones del mismo lote no den lugar a que se vuelvan a insertar las mismas filas. Consulta la documentación sobre insert_deduplication_token para obtener más información sobre cómo usar esta configuración.