Skip to content

How to Query Recent CDC Tables in ClickHouse

May 2026

In ClickHouse, recent CDC queries are mostly about knowing when FINAL matters and when a timestamp column should do the filtering.

Short Answer

To query recent CDC tables in ClickHouse, read the final-state table and use a real business timestamp for your recent window, but add FINAL when you need immediate point-in-time correctness on freshly mutated keys. That is the practical way to handle ReplacingMergeTree tables whose background merges may not have converged yet.

If you need recent deletes, check the companion tombstone table rather than trying to infer deletes from missing rows. The _skippr_order_token column exists to rank competing mutations, not to serve as your user-facing time dimension.

Why Teams Struggle with This

This matters because ClickHouse can briefly show multiple versions of the same business key right after CDC writes. A query that is technically fast but reads before merges converge can still be the wrong query for a freshness-sensitive dashboard.

  • Use FINAL when duplicate versions on fresh data would create a wrong answer.
  • Avoid relying on _skippr_order_token as if it were a readable event timestamp.
  • Keep a source-derived updated_at or committed_at column when readers need recent windows.
  • Use tombstones for delete visibility instead of guessing from absence.

How Skippr Handles It

Skippr makes this easier by documenting the ClickHouse caveat directly: ReplacingMergeTree converges through background merges, and FINAL is the way to force point-in-time consistency when the query cannot wait. The CDC design still gives you tombstones and order-token ranking, so the pieces are explicit.

A concrete example: if a dashboard needs the latest state of orders changed in the last hour, query the orders table with FINAL and filter on updated_at >= now() - INTERVAL 1 HOUR. If you also need deleted orders, read _skippr_tombstones_orders for the same business keys or time window.

  • Recent current-state reads come from the target table, optionally with FINAL.
  • Recent delete reads come from the companion tombstone table.
  • The order token is for conflict resolution, not for human recency semantics.
  • ClickHouse query correctness depends on understanding merge timing, not only table names.

What the First Useful Version Looks Like

The ClickHouse version of this question is not "where is the latest row stored." It is "do I need convergence now or can I wait for background merges."

Once that trade-off is explicit, recent CDC queries become much more predictable.