clickhouse
muxammadmamajonov/dot-claude/.claude/skills/clickhouse/SKILL.md
Use when the project uses ClickHouse — OLAP analytics, event ingestion, time-series, log storage, table engines, materialized views, sharding/replication, slow analytic queries.
Skill0 starsChanged 3 months ago
What's in it
- ClickHouse Skill
- When to use
- Workflow
- Standards
- Do
- Do not
- Common mistakes to avoid
- Output format
- Related checklists
- Related agents
---
name: clickhouse
description: Use when the project uses ClickHouse — OLAP analytics, event ingestion, time-series, log storage, table engines, materialized views, sharding/replication, slow analytic queries.
---
# ClickHouse Skill
## When to use
- Designing ClickHouse schemas for event streams, log pipelines, or analytical dashboards
- Choosing the right table engine (MergeTree family, ReplacingMergeTree, AggregatingMergeTree, CollapsingMergeTree, Distributed)
- Writing efficient OLAP queries (aggregations, window functions, array operations)
- Setting up materialized views for pre-aggregation
- Configuring replication with ClickHouse Keeper or ZooKeeper
- Ingesting data from Kafka, S3, HTTP, or other ClickHouse engines
- Diagnosing slow queries via `EXPLAIN`, `system.query_log`, and `system.parts`
---
## Workflow
1. **Define the query patterns first** — ClickHouse schema design is query-driven. Know the top 5 queries that must be fast before choosing an ORDER BY key or partition expression.
2. **Choose the table engine**:
- `MergeTree` — default; immutable append-only facts.
- `ReplacingMergeTree` — deduplicate rows by primary key (eventual; use `FINAL` in queries to force merge).
- `AggregatingMergeTree` — store partial aggregation states for incremental rollups.
- `CollapsingMergeTree` — OLAP-style deletes via sign column.
- `Distributed` — query shard cluster; always back it with local replicated tables.
- `Kafka` — read directly from Kafka topics (use as a source, not a storage engine).
3. **Design the ORDER BY (primary key) carefully** — ClickHouse stores data sorted by the `ORDER BY` columns. Put low-cardinality columns first (e.g. `(event_type, toDate(timestamp), user_id)`). The primary key determines sparse index granularity.
4. **Set a `PARTITION BY` clause** — use date-level granularity for time-series: `PARTITION BY toYYYYMM(timestamp)`. This enables partition pruning and TTL-based data expiry.
5. **Use materialized views for pre-aggregation** — create a target `AggregatingMergeTree` table and a `MATERIALIZED VIEW` that feeds into it on insert. This moves computation from query time to ingest time.
6. **Batch inserts** — never insert one row at a time. Minimum effective batch: 1 000 rows; recommended: 10 000–100 000 rows per INSERT. Use the async insert mode (`async_insert=1`) for high-frequency small-batch sources.
7. **Tune with `EXPLAIN`** — run `EXPLAIN indexes=1 <query>` to confirm index granules are being skipped. If `Granules: <large number>`, revisit ORDER BY or add a skip index.
8. **Set TTL** for automatic data expiry: `TTL timestamp + INTERVAL 90 DAY DELETE`.
9. **Monitor** via `system.query_log`, `system.parts`, `system.merges`. Alert on merge queue depth and part count per table (`SELECT count() FROM system.parts WHERE table = 'events' AND active`).
---
## Standards
### Do
- Use `UInt32`/`UInt64` for IDs and counters — smaller types compress better and query faster than `String` UUIDs unless UUID comparison is required.
- Use `LowCardinality(String)` for columns with < ~10 000 distinct values (event type, status, country code).
- Use `Nullable(T)` sparingly — nullable columns disable some optimizations; prefer a sentinel value (empty string, 0) when the null state has no semantic meaning.
- Compress columns explicitly for high-cardinality strings: `CODEC(ZSTD(3))`.
- Run DDL changes (ADD COLUMN, DROP COLUMN) on all replicas via the `ON CLUSTER` clause in replicated setups.
- Test queries on a sampled dataset: `SELECT … FROM table SAMPLE 0.01` before running on the full table.
### Do not
- Do not use `JOIN` as the primary access pattern — ClickHouse is optimized for denormalized wide tables. Pre-join data at ingest or use dictionaries for small reference tables.
- Do not `UPDATE` or `DELETE` rows frequently — mutations in ClickHouse are expensive async rewrites. Use `ReplacingMergeTree` or `CollapsingMergeTree` for mutable data.
- Do not `SELECT *` in OLAP queries — ClickHouse is columnar; reading unused columns wastes I/O.
- Do not use `ORDER BY rand()` for sampling — use `SAMPLE` clause or `sipHash64(id) % N = 0`.
- Do not create more than ~500 partitions per table — too many small parts degrade merge performance.
- Do not expose ClickHouse's native TCP port (9000) or HTTP port (8123) to the internet without authentication and TLS termination.
---
## Common mistakes to avoid
| Mistake | Consequence | Fix |
|---|---|---|
| Wrong ORDER BY (high-cardinality first) | Index granules not skipped; full scan on every query | Put low-cardinality columns first in ORDER BY |
| Inserting one row per INSERT | Extremely slow ingest; merge storm | Buffer inserts client-side; send 10k+ rows per batch |
| Using `ReplacingMergeTree` without `FINAL` | Duplicate rows returned | Append `FINAL` to SELECT, or use `GROUP BY` with `argMax` |
| Too many partitions (daily partition on 3 years of data) | 1000+ parts per table; slow queries | Switch to monthly partition; merge old partitions with `OPTIMIZE TABLE … FINAL` |
| Missing `ON CLUSTER` in DDL on replicated cluster | Schema drift between shards | Always suffix DDL with `ON CLUSTER <cluster_name>` |
| Not setting TTL | Unbounded disk growth | Define TTL at table creation; add TTL to existing tables with `ALTER TABLE … MODIFY TTL` |
| Using `String` for UUIDs in JOINs | Poor join performance | Use `UUID` type or `UInt64` hash of UUID |
---
## Output format
Table definition pattern:
```sql
CREATE TABLE events
(
timestamp DateTime64(3) CODEC(Delta, ZSTD(1)),
event_type LowCardinality(String),
user_id UInt64,
session_id UInt64,
properties String CODEC(ZSTD(3))
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(timestamp)
ORDER BY (event_type, toDate(timestamp), user_id)
TTL timestamp + INTERVAL 365 DAY DELETE
SETTINGS index_granularity = 8192;
```
Materialized view pattern:
```sql
CREATE TABLE events_daily_agg
(
event_type LowCardinality(String),
date Date,
count AggregateFunction(count, UInt64)
)
ENGINE = AggregatingMergeTree()
ORDER BY (event_type, date);
CREATE MATERIALIZED VIEW events_daily_mv TO events_daily_agg AS
SELECT event_type, toDate(timestamp) AS date, countState() AS count
FROM events
GROUP BY event_type, date;
```
---
## Related checklists
- `.claude/checklists/performance.md`
- `.claude/checklists/database.md`
- `.claude/checklists/devops.md`
## Related agents
- `.claude/agents/engineering/backend-engineer.md`
- `.claude/agents/engineering/data-engineer.md`
- `.claude/agents/quality/performance-engineer.md`
More agent context in muxammadmamajonov/dot-claude
74 other files this repository gives its agents, the first 60 shown.
AGENTS.md
CLAUDE.md
Copilot instructions
Cursor rule
Skill
- ai-ml.claude/skills/ai-ml/SKILL.md
- analytics.claude/skills/analytics/SKILL.md
- api-design.claude/skills/api-design/SKILL.md
- architecture.claude/skills/architecture/SKILL.md
- aws.claude/skills/aws/SKILL.md
- azure.claude/skills/azure/SKILL.md
- backend.claude/skills/backend/SKILL.md
- blockchain.claude/skills/blockchain/SKILL.md
- browser-extension.claude/skills/browser-extension/SKILL.md
- cli.claude/skills/cli/SKILL.md
- cloudflare.claude/skills/cloudflare/SKILL.md
- data-modeling.claude/skills/data-modeling/SKILL.md
- data-platform.claude/skills/data-platform/SKILL.md
- desktop.claude/skills/desktop/SKILL.md
- devops.claude/skills/devops/SKILL.md
- discovery.claude/skills/discovery/SKILL.md
- docker-kubernetes.claude/skills/docker-kubernetes/SKILL.md
- documentation.claude/skills/documentation/SKILL.md
- dotnet.claude/skills/dotnet/SKILL.md
- firebase.claude/skills/firebase/SKILL.md
- flutter.claude/skills/flutter/SKILL.md
- game.claude/skills/game/SKILL.md
- gcp.claude/skills/gcp/SKILL.md
- go-backend.claude/skills/go-backend/SKILL.md
- godot.claude/skills/godot/SKILL.md
- headless-automation.claude/skills/headless-automation/SKILL.md
- iot-embedded.claude/skills/iot-embedded/SKILL.md
- java-spring.claude/skills/java-spring/SKILL.md
- mcp-integration.claude/skills/mcp-integration/SKILL.md
- memory-management.claude/skills/memory-management/SKILL.md
- messaging-queues.claude/skills/messaging-queues/SKILL.md
- mobile.claude/skills/mobile/SKILL.md
- mongodb.claude/skills/mongodb/SKILL.md
- mysql.claude/skills/mysql/SKILL.md
- native-android.claude/skills/native-android/SKILL.md
- native-ios.claude/skills/native-ios/SKILL.md
- node-backend.claude/skills/node-backend/SKILL.md
- observability.claude/skills/observability/SKILL.md
- payments.claude/skills/payments/SKILL.md
- performance.claude/skills/performance/SKILL.md
- php-laravel.claude/skills/php-laravel/SKILL.md
- postgres.claude/skills/postgres/SKILL.md
- production-readiness.claude/skills/production-readiness/SKILL.md
- project-classification.claude/skills/project-classification/SKILL.md
- python-backend.claude/skills/python-backend/SKILL.md
- react-native.claude/skills/react-native/SKILL.md
- react-next.claude/skills/react-next/SKILL.md
- realtime.claude/skills/realtime/SKILL.md
- redis.claude/skills/redis/SKILL.md
- requirements-engineering.claude/skills/requirements-engineering/SKILL.md
- routine-authoring.claude/skills/routine-authoring/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

