Real-Time Analytics ClickHouse Workshop for CTOs and Data Architects

A ClickHouse workshop for CTOs and data architects has one job that a ClickHouse workshop for engineers does not: it has to end in decisions. Whether ClickHouse fits the workload at all, what it will cost at the row counts the business is actually forecasting, how the migration is cut over without a parity incident, and who on the team is allowed to carry the pager afterwards. ChistaDATA University runs exactly that ClickHouse workshop, and this post walks through the three days as we deliver them, with the lab evidence participants see rather than a syllabus.

Everything measured below was run on ClickHouse 26.8.2.7 LTS on a deliberately small single node (2 vCPU, 7 GB RAM, a 3.2 GB server memory cap) against 40 million synthetic events. The absolute numbers are meaningless for your estate; the shapes, the ratios and the mistakes are what transfer, which is the same rule we apply inside the ClickHouse workshop itself. For the full ClickHouse training ladder that surrounds this workshop, see the ChistaDATA University programs and our earlier piece on ClickHouse certification tiers.

ClickHouse workshop for CTOs and data architects: three-day agenda covering architecture and fit, measured cost, and migration and people decisions
Figure 1. The three days of the ClickHouse workshop, each built around a decision and ending in a written artefact.

Who this ClickHouse workshop is for, and what it is not

The audience is the sponsoring executive and the person who will own the architecture: a CTO, a VP of engineering or data, a principal or chief data architect, and usually the platform lead who will inherit the cluster. It is the decision-level counterpart of the CHT-900 executive track in the ChistaDATA University catalogue, extended with the architecture material that data architects need in order to sign off on a design rather than just approve a budget.

It is not ClickHouse training for operators. Nobody leaves this ClickHouse workshop able to run a Keeper quorum recovery at three in the morning; that is what the CHT-300 and CHT-400 programs are for, and the workshop ends with an explicit view of which engineers should go into which of those. It is also not a vendor pitch. ChistaDATA works only on open-source ClickHouse, so the “should you use ClickHouse at all” session on day one is allowed to conclude with “not for this workload,” and sometimes does.

Delivery follows the standard ChistaDATA University formats: three to five consecutive on-site days taught against your own schema and data volumes under NDA, or an instructor-led virtual series with a shared lab cluster per cohort. Every claim made in the room is reproduced on a live multi-node cluster, not a slide, and the labs run on the same environment specification as every other ClickHouse workshop we deliver: a dedicated cluster per group with three shards and two replicas each, a three-node ClickHouse Keeper ensemble, Kafka or Redpanda, Prometheus and Grafana, MinIO for object-storage tiers, and a Kubernetes cluster with the ClickHouse operator.

Day one of the ClickHouse workshop: architecture and fit

Day one answers the question most ClickHouse education skips because it is uncomfortable: where does ClickHouse lose? We work through the workload profiles where it wins decisively (append-heavy event streams, wide-scan aggregations, sub-second dashboards over billions of rows) and the profiles where it does not (row-level transactional updates, point lookups by non-key columns at high concurrency, workloads that need multi-statement ACID). Snowflake, BigQuery, Redshift, Druid and Pinot are each compared against the same workload sheet, using their own documentation for their claims.

The architecture half of the day is anchored on one reference topology, drawn below with the versions we teach against. Data architects leave with this diagram annotated for their own workload, which is why we insist on doing this session against real schemas whenever the engagement allows it.

ClickHouse workshop reference real-time analytics topology on ClickHouse 26.8 LTS: Kafka into three shards by two replicas with a three-node ClickHouse Keeper quorum, object storage tier and Prometheus Grafana
Figure 2. The reference topology every data architect annotates for their own workload on day one of the ClickHouse workshop.

The first piece of code participants see is the ingestion spine of that topology: a Kafka engine table, a materialized view, and a replicated storage table. We show the replicated form because that is what production looks like, and we run the single-node equivalent in the lab so that every architect executes it personally rather than watching.

-- Reference ingestion spine taught in the ClickHouse workshop (ClickHouse 26.8 LTS syntax)
-- 1. Kafka engine table: a consumer, not storage. Never query it directly in production.
CREATE TABLE analytics.events_kafka
(
    event_time   DateTime64(3),
    tenant_id    UInt32,
    user_id      UInt64,
    event_type   LowCardinality(String),
    page_path    String,
    duration_ms  UInt32,
    bytes_out    UInt64,
    country      LowCardinality(String)
)
ENGINE = Kafka
SETTINGS
    kafka_broker_list        = '${KAFKA_BROKERS}',
    kafka_topic_list         = 'product-events',
    kafka_group_name         = 'clickhouse-events-v1',
    kafka_format             = 'JSONEachRow',
    kafka_num_consumers      = 2,
    kafka_max_block_size     = 65536;

-- 2. Replicated storage table: explicit engine parameters, explicit sort key, explicit partition.
CREATE TABLE analytics.events_local ON CLUSTER 'analytics_cluster'
(
    event_date   Date DEFAULT toDate(event_time),
    event_time   DateTime64(3),
    tenant_id    UInt32,
    user_id      UInt64,
    event_type   LowCardinality(String),
    page_path    String,
    duration_ms  UInt32,
    bytes_out    UInt64,
    country      LowCardinality(String)
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/analytics/events_local', '{replica}')
PARTITION BY toYYYYMM(event_date)
ORDER BY (tenant_id, event_date, event_type)
TTL event_date + INTERVAL 13 MONTH TO VOLUME 'cold'
SETTINGS index_granularity = 8192;

-- 3. The materialized view is the only thing that moves rows from Kafka into storage.
CREATE MATERIALIZED VIEW analytics.mv_events_ingest TO analytics.events_local AS
SELECT
    toDate(event_time) AS event_date,
    event_time, tenant_id, user_id, event_type, page_path, duration_ms, bytes_out, country
FROM analytics.events_kafka;

Three design decisions are argued out loud around this DDL, because they are the ones architects most often get wrong on their first ClickHouse deployment: the sort key leads with the column every dashboard filters on (tenant_id), not the timestamp; the partition key is monthly rather than daily so that part counts stay sane at high insert rates; and the TTL moves cold months to an object-storage volume rather than deleting them, which is what makes the day-two cost model work.

Day two of the ClickHouse workshop: what it will cost, measured

Total cost of ownership is where a ClickHouse workshop for executives earns its fee, because the honest answer depends on compression ratios nobody can quote from a datasheet. We measure them. The first query of the day reads system.parts and turns it into the number a CFO understands: disk per billion rows.

SELECT
    formatReadableSize(sum(data_uncompressed_bytes))                          AS logical,
    formatReadableSize(sum(data_compressed_bytes))                            AS on_disk,
    round(sum(data_uncompressed_bytes) / sum(data_compressed_bytes), 2)       AS ratio,
    round(sum(data_compressed_bytes) / sum(rows), 1)                          AS bytes_per_row_on_disk,
    formatReadableSize(sum(data_compressed_bytes) / sum(rows) * 1000000000)   AS disk_per_billion_rows
FROM system.parts
WHERE database = 'analytics' AND table = 'events_local' AND active
FORMAT Vertical;
logical:               2.71 GiB
on_disk:               1.06 GiB
ratio:                 2.57
bytes_per_row_on_disk: 28.3
disk_per_billion_rows: 26.38 GiB

Those 28 bytes per row are on uniformly random synthetic data, which compresses about as badly as data can; real product telemetry with monotonic timestamps and skewed values routinely lands well under ten. The point of the exercise is not the number, it is that participants now know how to produce the number for their own data before anyone signs a storage forecast. The same session covers self-managed versus managed-service economics and the egress and object-storage cost behaviour that the TTL-to-cold-volume design above depends on.

The rollup decision, including the version that did not work

The second half of day two is the design decision architects ask about most: pre-aggregate with materialized views, or let ClickHouse scan raw rows? We answer it by building both and reading system.query_log. The dashboard query in question is “purchase events per tenant for the first three weeks of August,” run cold with the query condition cache and mark cache dropped between runs.

-- Counts-only hourly rollup: SummingMergeTree, plain numeric columns, no aggregate states
CREATE TABLE analytics.events_1h_counts
(
    bucket           DateTime,
    tenant_id        UInt32,
    event_type       LowCardinality(String),
    events           UInt64,
    duration_ms_sum  UInt64,
    bytes_out        UInt64
)
ENGINE = SummingMergeTree((events, duration_ms_sum, bytes_out))
PARTITION BY toYYYYMM(bucket)
ORDER BY (tenant_id, event_type, bucket);

CREATE MATERIALIZED VIEW analytics.mv_events_1h_counts TO analytics.events_1h_counts AS
SELECT
    toStartOfHour(event_time) AS bucket,
    tenant_id,
    event_type,
    count()                   AS events,
    sum(duration_ms)          AS duration_ms_sum,
    sum(bytes_out)            AS bytes_out
FROM analytics.events_local
GROUP BY bucket, tenant_id, event_type;
-- The same rollup with uniq and quantile aggregate states: AggregatingMergeTree
CREATE TABLE analytics.events_1h_rollup
(
    bucket        DateTime,
    tenant_id     UInt32,
    event_type    LowCardinality(String),
    events        AggregateFunction(count),
    users         AggregateFunction(uniq, UInt64),
    p95_duration  AggregateFunction(quantile(0.95), UInt32)
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(bucket)
ORDER BY (tenant_id, event_type, bucket);

Here is what the three versions of the dashboard query cost, straight from system.query_log, alongside what each table occupies on disk for the August partition:

   ┌─source───────────┬──ms─┬─read_rows─┬─read───────┬─mem────────┐
1. │ events_local     │ 105 │   9500000 │ 172.14 MiB │ 1.53 MiB   │   -- raw scan, count() + avg()
2. │ events_1h_counts │  24 │   1094172 │ 34.43 MiB  │ 1.70 MiB   │   -- SummingMergeTree rollup
3. │ events_local     │ 217 │   9500000 │ 172.14 MiB │ 28.54 MiB  │   -- raw scan, uniq() + quantile()
4. │ events_1h_rollup │ 373 │   1094172 │ 251.48 MiB │ 39.81 MiB  │   -- AggregatingMergeTree rollup
   └──────────────────┴─────┴───────────┴────────────┴────────────┘

   ┌─table────────────┬─on_disk────┬─row_count─┐
1. │ events_local     │ 256.64 MiB │   9500000 │
2. │ events_1h_counts │ 12.03 MiB  │   1094172 │
3. │ events_1h_rollup │ 74.89 MiB  │   1094172 │
   └──────────────────┴────────────┴───────────┘
ClickHouse workshop rollup decision measured: SummingMergeTree rollup 4.4 times faster than the raw scan while an AggregatingMergeTree rollup with uniq and quantile states was slower than no rollup
Figure 3. The rollup decision as measured in the ClickHouse workshop lab: one materialized view helps, the other hurts.

The counts rollup did what everyone expects: 4.4 times faster, one fifth of the bytes read, one twentieth of the disk. The rollup carrying uniq and quantile states did the opposite. It was slower than scanning the raw table and read more bytes, because on this data every event has an almost unique user_id, so each hourly group’s uniq state is heavier than the eight or nine raw rows it summarises.

A rollup only pays when rows per group is large and the state per group is small, and no amount of ClickHouse education replaces measuring that ratio on your own data. We leave this result in the ClickHouse workshop deliberately, because the architects who see it stop proposing “just add a materialized view” as a reflex.

The first attempt at backfilling the state rollup also failed, and we keep that in too:

Code: 241. DB::Exception: (total) memory limit exceeded: would use 3.21 GiB
(attempt to allocate chunk of 6.90 MiB), current RSS: 6.82 MiB, maximum: 3.20 GiB.
OvercommitTracker decision: Query was selected to stop by OvercommitTracker. (MEMORY_LIMIT_EXCEEDED)
-- The fix is not a bigger box; it is letting the aggregation spill, and bucketing coarser.
INSERT INTO analytics.events_1h_rollup
SELECT
    toStartOfHour(event_time),
    tenant_id,
    event_type,
    countState(),
    uniqState(user_id),
    quantileState(0.95)(duration_ms)
FROM analytics.events_local
WHERE event_date >= '2026-08-01'
GROUP BY 1, 2, 3
SETTINGS
    max_insert_threads                = 2,
    max_bytes_before_external_group_by = 1000000000,
    max_memory_usage                   = 2500000000;

Five-minute buckets across 400 tenants and six event types exceeded the lab’s 3.2 GB cap; hourly buckets with max_bytes_before_external_group_by completed in under five seconds. Executives in the room learn what a memory limit error actually means, and architects learn that the settings to reach for are on the query, not the purchase order.

Day three of the ClickHouse workshop: migration risk and cutover

Day three is built around one pattern, dual-write with shadow-read, because it is the migration shape that lets a CTO commit to a cutover date without betting the quarter on it. Writes go to both the legacy store and ClickHouse; reads stay on legacy while ClickHouse is queried in the shadow and the results are compared; the cutover criterion is written down before the migration starts, not negotiated during it.

ClickHouse workshop migration pattern: dual-write with shadow-read into ClickHouse 26.8 LTS, a parity-query cutover gate and a rollback that deletes nothing
Figure 4. Dual-write with shadow-read, the migration pattern day three of the ClickHouse workshop is built around.

The technical artefact of the day is the parity check, and we run it on the lab against a migrated copy of the August partition so participants see what “parity” means as a query rather than a slide:

-- Data-parity verification between the legacy-shaped table and the migrated table
SELECT
    toYYYYMM(event_date)                                                     AS partition,
    countIf(src = 'legacy')                                                  AS rows_legacy,
    countIf(src = 'migrated')                                                AS rows_migrated,
    sumIf(bytes_out, src = 'legacy') - sumIf(bytes_out, src = 'migrated')    AS bytes_out_delta,
    sumIf(h, src = 'legacy') = sumIf(h, src = 'migrated')                    AS row_hash_match
FROM
(
    SELECT 'legacy'   AS src, event_date, bytes_out,
           cityHash64(tenant_id, user_id, event_time, event_type, page_path, duration_ms, bytes_out) AS h
    FROM analytics.events_local
    WHERE event_date >= '2026-08-01'
    UNION ALL
    SELECT 'migrated' AS src, event_date, bytes_out,
           cityHash64(tenant_id, user_id, event_time, event_type, page_path, duration_ms, bytes_out) AS h
    FROM analytics.events_codec
)
GROUP BY partition;
   ┌─partition─┬─rows_legacy─┬─rows_migrated─┬─bytes_out_delta─┬─row_hash_match─┐
1. │    202608 │     9500000 │       9500000 │               0 │              1 │
   └───────────┴─────────────┴───────────────┴─────────────────┴────────────────┘

Row counts, a business-metric delta and a summed row hash, per partition. The cutover criterion we recommend is that this query returns a match for every partition in scope on three consecutive days of dual writes, and that the shadow-read latency p95 is inside the target. Rollback is the mirror image: reads flip back to legacy, dual writes continue, nothing is deleted until the criterion holds again. The afternoon covers the two decisions that outlive the migration: team capability planning (which roles carry the on-call rotation, what the readiness sign-off looks like, hiring versus upskilling through the CHT ladder) and governance (GDPR erasure in an append-optimised engine, audit logging, SOC 2 and HIPAA control mapping).

What participants leave the ClickHouse workshop with

Every ChistaDATA University engagement ends with written artefacts, and this ClickHouse workshop is no exception. Participants leave with the reference topology annotated for their workload, the fit assessment with the “where ClickHouse loses” section filled in honestly, a storage and cost model built from their own compression ratios, a rollup decision record with the measured cost of each candidate view, the dual-write cutover plan with its parity query and rollback path, and a role-by-role ClickHouse training recommendation mapped onto CHT-100 through CHT-500. When the workshop is followed by a ClickHouse support or managed-services engagement, those documents become the first section of the support bench’s briefing pack.

FormatStructureBest for
On-site ClickHouse workshopThree to five consecutive days, eight hours a day, taught against your own schema and data volumes under NDATeams starting a migration or hardening a new deployment, with the sponsoring executive in the room
Instructor-led virtualTwo live sessions a week, recorded, with office hours and a shared lab cluster per cohortDistributed leadership and architecture teams across time zones
Executive briefing series (CHT-900)A condensed 10-hour briefing series that runs alongside the engineering programsCTOs and CXOs who need the decision-level view without the lab days
Embedded mentorshipA ChistaDATA principal engineer joins sprint ceremonies and code review for a fixed number of hours a weekArchitects already in production who need design coaching rather than classroom time

Contracting follows the same six stages as every other ChistaDATA University program: a discovery call, a skills assessment, a syllabus and statement of work, delivery, certification where applicable, and thirty days of aftercare lab access. The first two stages are free of charge and produce a written scope before any commitment. Cohort licensing with volume tiers, multi-year enterprise agreements and purchase-order friendly contracting are all available.

Key takeaways from the ClickHouse workshop

  • A ClickHouse workshop for CTOs and data architects has to end in decisions, so every session is built around one: fit, cost, cutover, and capability.
  • Fit is assessed honestly, including the workloads where ClickHouse loses to a transactional store or a managed warehouse; the recommendation can be “not this one.”
  • Cost is measured, not quoted. Participants produce disk-per-billion-rows from system.parts on their own data; on the lab’s worst-case random data it was 26 GiB per billion rows at 28 bytes a row.
  • Rollups are a measured design choice. A counts-only SummingMergeTree view was 4.4 times faster than the raw scan; the same view carrying uniq and quantile states was slower than no view at all.
  • Migration is dual-write with shadow-read, a written cutover criterion, and a parity query that compares row counts, a business metric and a row hash per partition.
  • The workshop is the executive and architecture layer of ClickHouse education at ChistaDATA University; engineers continue into CHT-100 through CHT-500 ClickHouse training with a role-by-role recommendation.

ClickHouse workshop FAQ

Who should attend a ClickHouse workshop for CTOs and data architects?

The sponsoring executive (CTO, VP of engineering or data), the architect who will own the design, and the platform lead who will inherit the cluster. It is the decision-level layer of ChistaDATA University; operators and developers belong in the CHT-100 to CHT-400 ClickHouse training programs.

Does the ClickHouse workshop need prior ClickHouse experience?

No. The architecture material is taught from first principles at decision level. Architects who already run ClickHouse in production get more out of the rollup and migration days, and the free 45-minute skills assessment before the engagement tells us how to pitch each session.

Is the ClickHouse workshop delivered on our own data?

For corporate engagements, yes. Under NDA the sample datasets are replaced with your schemas, query patterns and latency targets, so the fit assessment, cost model and parity check are built on your platform rather than an example.

How does the workshop relate to ClickHouse certification and the CHT programs?

The workshop is the executive and architecture counterpart of the CHT-900 track and does not itself confer certification. It ends with a role-by-role recommendation into the CHT-100 through CHT-500 ClickHouse training ladder, where certification is earned through a proctored exam and a capstone defence on a live cluster.

The standing caveat applies to every command shown here: test on staging with your own workload before touching production, keep a verified backup and a rehearsed restore, and treat the DR replica as part of the estate you are designing. To scope a ClickHouse workshop for your leadership and architecture team, request a ClickHouse training proposal or call (844) 395-5717; the discovery call and skills assessment carry no charge.

Sources: ChistaDATA University programs, ClickHouse Kafka table engine, AggregatingMergeTree, SummingMergeTree, max_bytes_before_external_group_by. Lab: ClickHouse 26.8.2.7 LTS, 2 vCPU / 7 GB, 40 million synthetic rows, single node.

About ChistaDATA Inc. 259 Articles
ChistaDATA is a full-stack ClickHouse infrastructure operations company delivering consulting, 24×7 enterprise support, and managed services, with core expertise in performance engineering, scalability, and data SRE. Headquartered in California, our consulting and support engineering teams operate from San Francisco, Vancouver, London, Germany, Russia, Ukraine, Australia, Singapore, and India, providing follow-the-sun, enterprise-class consultative support around the clock. We work closely with more than 200 customers globally, including some of the largest planet-scale internet properties, financial-services institutions, consumer brands, and industrial IoT programmes.