Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Design ClickHouse schemas with MergeTree engines, ORDER BY keys, and partitioning. Use when creating new tables, choosing an engine, designing sort keys, or modeling data for analytical workloads on ClickHouse or ClickHouse Cloud. Trigger with "clickhouse schema design", "clickhouse table design", "clickhouse ORDER BY", "clickhouse partitioning", "MergeTree table".
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 73% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 34% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 62% | 0% |
| case-17 | ✓→✓ | = Same ✓ | 20% | 0% |
| case-22 | ✓→✓ | = Same ✓ | 28% | 0% |
Design ClickHouse tables with correct engine selection, ORDER BY keys, partitioning, and codec choices for analytical workloads. This skill covers the four schema decisions that determine query speed and storage cost — engine, sort key, partition expression, and column codecs — then points to references/ for full DDL and the programmatic apply path.
@clickhouse/client connected (see clickhouse-install-auth)| Engine | Best For | Dedup? | Example | |--------|----------|--------|---------| | MergeTree | General analytics, append-only logs | No | Clickstream, IoT | | ReplacingMergeTree | Mutable rows (upserts) | Yes (on merge) | User profiles, state | | SummingMergeTree | Pre-aggregated counters | Sums numerics | Page view counts | | AggregatingMergeTree | Materialized view targets | Merges states | Dashboards | | CollapsingMergeTree | Stateful row updates | Collapses +-1 | Shopping carts |
ClickHouse Cloud uses SharedMergeTree — it is a drop-in replacement for MergeTree on Cloud. You do not need to change your DDL.
The ORDER BY clause is the single most important schema decision. It defines:
Rules of thumb:
event_type, status)user_id, tenant_id)created_at)sql-- Good: filter by tenant, then by time ranges ORDER BY (tenant_id, event_type, created_at) -- Bad: UUID first means every query scans the full index ORDER BY (event_id, created_at) -- event_id is random UUID
Start from the append-only event skeleton below, then adapt the engine and sort key to your access pattern. Full DDL for the three canonical shapes — event analytics (MergeTree), user profiles (ReplacingMergeTree), and daily aggregation (AggregatingMergeTree) — plus column codec choices is in schema examples.
sqlCREATE TABLE analytics.events ( event_id UUID DEFAULT generateUUIDv4(), tenant_id UInt32, event_type LowCardinality(String), user_id UInt64, properties String CODEC(ZSTD(3)), -- JSON blob, compress well created_at DateTime64(3) DEFAULT now64(3) ) ENGINE = MergeTree() ORDER BY (tenant_id, event_type, toDate(created_at), user_id) PARTITION BY toYYYYMM(created_at) TTL created_at + INTERVAL 1 YEAR SETTINGS index_granularity = 8192;
toYYYYMM(date) (monthly) is the right default for most time-series tables — target 10-1000 parts per partition. Each partition creates separate parts on disk, so over-partitioning (e.g., by user_id) creates millions of tiny parts and kills performance. Full partition matrix and the Node.js apply path are in partitioning and applying schema.
Applying this skill produces:
CREATE TABLE statement with an engine, ORDER BY sort key,PARTITION BY expression, per-column codecs, and (optionally) a TTL clause.
why this partition granularity — so the schema is reviewable, not cargo-culted.
@clickhouse/client command() call that runsthe DDL from application code (see the reference), keeping schema in version control alongside the service.
| Error | Cause | Solution | |-------|-------|----------| | ORDER BY expression not in primary key | PRIMARY KEY != ORDER BY | Remove explicit PRIMARY KEY or align | | Too many parts (300+) | Over-partitioning | Use coarser partition expression | | Cannot convert String to UInt64 | Wrong data type | Match insert types to schema | | TTL expression type mismatch | TTL on non-date column | TTL must reference DateTime column |
MergeTree, sort key (tenant_id, event_type,toDate(created_at), user_id), monthly partitions, 1-year TTL.
ReplacingMergeTree(updated_at),ORDER BY user_id, read with FINAL for deduplicated rows.
AggregatingMergeTree targeting amaterialized view, storing AggregateFunction(uniq, UInt64) state.
Full DDL for all three shapes plus column codec choices: schema examples. The Node.js apply path (client.command() with @clickhouse/client) and the full partition matrix: partitioning and applying schema.
For inserting and querying data — batch inserts, async inserts, and query patterns against these tables — see clickhouse-core-workflow-b.
Other measured skills in the registry, with their headline benchmark lift.