Why do I still see two rows for one key?
Merges are asynchronous. Query with FINAL, or GROUP BY key and take argMax(column, updated_at), until the background merge collapses them.
Generador de upsert
Nombra tu tabla, clave y columnas y obtén la sentencia que ClickHouse acepta de verdad, con una guarda para que una fila antigua nunca sobrescriba una nueva. Debajo: cómo funciona la mecánica, qué se rompe y cómo Datrise carga ClickHouse de forma incremental.
Las notas técnicas de esta página están en inglés.
Sentencia · INSERT into ReplacingMergeTree + FINAL
-- Declare the target once; the ORDER BY key is the dedupe key and
-- the version column decides which duplicate survives a merge:
-- ENGINE = ReplacingMergeTree(updated_at) ORDER BY (id)
INSERT INTO deals (id, name, stage, amount, owner_id, updated_at)
SELECT id, name, stage, amount, owner_id, updated_at
FROM deals_staging;
-- Reads must ask for the collapsed view; merges are asynchronous.
SELECT id, name, stage, amount, owner_id, updated_at
FROM deals FINAL;ClickHouse does not upsert on write. The idiom is a ReplacingMergeTree table: you INSERT every version of a row, and background merges later collapse duplicates that share the ORDER BY key, keeping the one with the highest version column (updated_at in the generated statement). Until a merge runs, both versions exist, so reads use FINAL or argMax to see the current one.
That trade is what makes ClickHouse fast at ingest: inserts are append-only and cheap, and deduplication is deferred. Insert in large batches, thousands of rows at a time or with async_insert enabled, because each INSERT creates a data part and a table with too many parts throttles writes. Partition by month and order by (key, updated_at) so range scans and merges stay local.
Merges are asynchronous. Query with FINAL, or GROUP BY key and take argMax(column, updated_at), until the background merge collapses them.
No. It forces a full merge of every part and is expensive on large tables. Let merges run in the background and read with FINAL.
ReplacingMergeTree accepts an is_deleted column (ClickHouse 23.2+): insert the row with is_deleted = 1 and a newer version, and merges drop it. Lightweight DELETE also works but marks rows rather than removing them immediately.
Datrise aterriza entidades de CRM y SaaS en ClickHouse con esta misma mecánica, una marca de agua sobre updated-at y columnas tipadas, así que la sentencia de arriba es la que corre por ti. Únete a la lista de espera para acceso anticipado.
Explorar el catálogo de integraciones