← Previous Module 🏠 Home Next: Module 2 - Table Engines β†’

πŸ“Š MODULE 1

ClickHouse Fundamentals & Architecture
Duration: 4-6 hours | Week 1
πŸ“– What is ClickHouse?

ClickHouse in a Nutshell

ClickHouse is a column-oriented database management system (DBMS) for online analytical processing (OLAP). It's designed to handle massive volumes of data and execute complex analytical queries with sub-second response times. Think of it as a high-performance analytics engine that excels at aggregating, filtering, and analyzing billions of rows in real-time.

πŸ›οΈ

Column-Oriented Storage

Data is stored by columns, not rows, enabling incredible compression and query speed for analytical workloads.

⚑

Blazing Fast

Process billions of rows per second. Queries that take minutes in traditional databases run in milliseconds.

πŸ“ˆ

Horizontally Scalable

Scale out by adding more nodes. Handle petabytes of data across distributed clusters.

πŸ”„

Real-Time Analytics

Ingest and query data simultaneously. Perfect for real-time dashboards and monitoring.

ClickHouse Architecture Diagram

Client Application
↓
HTTP (8123) / TCP (9000)
↓
Query Processing Layer
Parser β†’ Optimizer β†’ Executor
↓
Storage Engine (MergeTree)
Column-Oriented Storage
↓
Disk Storage
SSD / NVMe / Distributed Storage

Column-Oriented vs Row-Oriented Storage

Row-Oriented Storage

Row 1: [1, Alice, 25, NYC, 50000]
Row 2: [2, Bob, 30, LA, 60000]
Row 3: [3, Carol, 35, SF, 70000]
Query: SELECT AVG(Salary)
❌ Reads ALL columns for ALL rows
Problem: Wastes I/O on unnecessary data

Column-Oriented Storage

Salary Column: [50000, 60000, 70000]
Age Column: [25, 30, 35]
Name Column: [Alice, Bob, Carol]
Query: SELECT AVG(Salary)
βœ… Reads ONLY Salary column
Advantage: 10-100x less I/O, incredibly fast!

MergeTree Architecture

Data Part 1
Partition: 202601
Primary Index
Data Blocks
Data Part 2
Partition: 202601
Primary Index
Data Blocks
Data Part 3
Partition: 202602
Primary Index
Data Blocks
Background Merge Process
Automatically combines parts for optimization
↓
Merged Part (Optimized)
Fewer parts = faster queries

ClickHouse vs Traditional Databases

Feature MySQL/PostgreSQL MongoDB ClickHouse
Storage Model Row-oriented Document-oriented Column-oriented
Best For OLTP, transactions Document storage, CRUD OLAP, analytics
Query Speed Slow on big datasets Moderate Extremely fast
Updates/Deletes Fast & frequent Fast & frequent Slow, avoid if possible
Compression Limited Limited Excellent (10-100x)
Joins Excellent Limited Good (but prefer denormalization)
πŸš€ Quick Start

1. Installation (Single Node)

🐧 Ubuntu/Debian

🍎 macOS

🐳 Docker (Fastest Way to Test)

2. First Steps - Create Database and Table

3. Verify Installation

πŸ’» Commands Reference

Database Operations

-- Create database
CREATE DATABASE my_db;

-- Create database with engine
CREATE DATABASE my_db ENGINE = Atomic;
-- Drop database
DROP DATABASE my_db;

-- Show all databases
SHOW DATABASES;

Table Operations (MergeTree Family)

Data Insertion

Query Operations

System & Monitoring Commands

✨ Best Practices

1. Data Modeling

❌ Bad

Problem: JOINs are expensive in ClickHouse

βœ… Good

Benefit: 10-100x faster queries, no JOINs

2. Partition Key Selection

❌ Bad

Problem: Creates 365+ partitions per year, degrades performance

βœ… Good

Benefit: Only 12 partitions per year, better performance, easier to drop old data

3. Ordering Key Selection

❌ Bad

Problem: Poor data compression, inefficient queries

βœ… Good

Benefit: Better compression, faster queries on country and time ranges

4. Avoid Frequent Updates/Deletes

⚠️ Important: ClickHouse is NOT designed for OLTP workloads

  • Inserts: Batch them! Insert 10,000+ rows at once, not one by one
  • Updates: Very slow. Use ReplacingMergeTree if you must update
  • Deletes: Very slow. Use TTL for automatic deletion or ALTER DELETE for rare cases

5. Hardware Considerations

πŸ’Ύ Storage

  • SSD is mandatory for good performance
  • NVMe SSDs are ideal for hot data
  • Plan for 10-100x compression ratio

🧠 Memory

  • Minimum: 8GB per server
  • Recommended: 64-256GB for production
  • More RAM = better query performance

βš™οΈ CPU

  • More cores = better parallelization
  • Minimum: 8 cores
  • Recommended: 16-64 cores for production

🌐 Network

  • 10 Gbps network for distributed clusters
  • Low latency between nodes is critical
  • Use dedicated network for replication
🎯 When to Use ClickHouse

βœ… Good For

  • Real-time analytics and dashboards
  • Time-series data (logs, metrics, events)
  • Business intelligence and reporting
  • Click-stream and web analytics
  • IoT sensor data analysis
  • Financial market data
  • Monitoring and observability (like Grafana)
  • Data warehousing for analytical queries
  • Large-scale aggregations (billions of rows)
  • Append-only workloads

❌ Not Good For

  • Transactional workloads (use MySQL/PostgreSQL)
  • Frequent updates/deletes (use OLTP databases)
  • Key-value lookups (use Redis/DynamoDB)
  • Document storage (use MongoDB/Elasticsearch)
  • Full-text search (use Elasticsearch/Meilisearch)
  • Small datasets (< 100 million rows)
  • Complex transactions with ACID guarantees
  • Graph databases (use Neo4j)
  • Real-time row-by-row processing
πŸ† Real-World Results
100-1000x

Faster Than MySQL

Analytical queries on large datasets run 100-1000x faster than traditional row-oriented databases

Billions/sec

Row Processing Speed

ClickHouse can process billions of rows per second on modern hardware

10-100x

Compression Ratio

Achieve 10-100x compression ratios with column-oriented storage and codecs

< 1 sec

Query Response Time

Sub-second response times for complex aggregations on billions of rows

Use Case Examples

πŸ“Š Web Analytics Platform

Challenge: Process 10 billion events per day, provide real-time dashboards

Solution: ClickHouse with Kafka streaming

Results:

  • Query response time: < 500ms for complex aggregations
  • Storage: 10TB raw data compressed to 500GB (20x compression)
  • Infrastructure cost reduced by 70% vs traditional data warehouse

πŸ“ˆ Real-Time Monitoring System

Challenge: Monitor 100,000 servers generating 1 million metrics/sec

Solution: ClickHouse cluster with 3 shards Γ— 2 replicas

Results:

  • Ingestion rate: 1M events/sec sustained
  • Query latency: 200-500ms for real-time alerts
  • Data retention: 90 days with automatic TTL cleanup

πŸ’³ Financial Transaction Analytics

Challenge: Analyze 500 million transactions per day for fraud detection

Solution: ClickHouse with ReplacingMergeTree for deduplication

Results:

  • Fraud detection queries: < 1 second on 6 months of data
  • Report generation time reduced from 2 hours to 5 minutes
  • Compliance reporting automated with materialized views
πŸ“‹ Ready-to-Use Templates

Template 1: Event Tracking Table

Template 2: Application Logs Table

Template 3: Metrics/Time-Series Table

Template 4: User Sessions Table

πŸ”₯ Advanced Patterns

1. Using Materialized Views for Pre-Aggregation

2. Optimizing with LowCardinality

3. Using Codecs for Better Compression

4. Sampling for Faster Queries

5. Distributed Queries Across Clusters

πŸ“š Related Resources

πŸ“˜ View in Notion

Access this module in your Notion workspace for note-taking and tracking your progress.

Open in Notion β†’

πŸ“– Official Documentation

πŸŽ“ Learning Resources

🎯 Next Steps

After completing Module 1, you should be comfortable with:

  • βœ… Understanding ClickHouse architecture and when to use it
  • βœ… Installing and running ClickHouse (single node)
  • βœ… Creating databases and basic MergeTree tables
  • βœ… Inserting data and running analytical queries
  • βœ… Understanding column-oriented storage benefits

Ready for Module 2? Next, we'll dive deep into Table Engines & Data Modeling!

🐳 Hands-on Docker Demo for this Module

A self-contained ClickHouse stack you can run locally. Every step is reproducible; the README below walks through each concept with diagrams and measured outcomes.

cd code-examples/demos/module-1-fundamentals
./up.sh        # bring stack up, wait for health
./run.sh       # run the demo (idempotent β€” re-runnable)
./down.sh      # tear down + drop volumes

πŸ“Ί Live demo capture

Recorded with vhs: the actual terminal output from ./run.sh running on this very stack.

Module demo GIF
Animated GIF, ~566 KB. Right-click β†’ open in new tab to view full-size.

✨ Animated concept diagrams

Inline SVG animations β€” no plugins, native browser playback. Each visualises a key flow this module covers.

Parts merge
Parts merge

πŸ“š ClickHouse reference visuals

Curated from the official ClickHouse documentation and engineering blog (and Altinity's docs/blog) β€” the same diagrams the broader CH community uses to explain these concepts. Click any image to read the source.

Animated row-oriented storage layout (data laid out per-row)
ClickHouse Docs Animated row-oriented storage layout (data laid out per-row)
Animated columnar storage layout (data laid out per-column)
ClickHouse Docs Animated columnar storage layout (data laid out per-column)
Row store vs column store: how the same table is physically laid out
ClickHouse Engineering Row store vs column store: how the same table is physically laid out
Why columns compress better than rows
ClickHouse Engineering Why columns compress better than rows
Columnar layout enables vectorised execution over batches
ClickHouse Engineering Columnar layout enables vectorised execution over batches

πŸ“š Full module reference

Module 1 β€” ClickHouse Fundamentals

Audience: engineers who'll deploy, query, or operate ClickHouse in production. Prerequisites: any prior SQL experience, a working Docker install. Time: ~45 min reading + 30 min hands-on.

This module establishes the mental model for everything that follows. By the end you will be able to:


1. The 30-second pitch

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "The 30-second pitch".

Here is a brief excerpt from the material I'm reading:

"""
ClickHouse is a **column-oriented OLAP DBMS** designed for one job: scan huge tables fast, returning aggregations in milliseconds. Three properties make it work: | Property                  | What it buys you                                                                                | | **Columnar storage**      | Each column is its own file β†’ analytical queries read only the columns they touch.              | | **Vectorised execution**  | Operators process arrays of values, not rows-one-at-a-time β†’ SIMD-friendly, cache-friendly.     | | **Sparse primary index**  | One mark per ~8192 rows...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

ClickHouse is a column-oriented OLAP DBMS designed for one job: scan huge tables fast, returning aggregations in milliseconds. Three properties make it work:

Property What it buys you
Columnar storage Each column is its own file β†’ analytical queries read only the columns they touch.
Vectorised execution Operators process arrays of values, not rows-one-at-a-time β†’ SIMD-friendly, cache-friendly.
Sparse primary index One mark per ~8192 rows β†’ indexes stay tiny even on trillion-row tables.
Aggressive compression Per-column codecs (LZ4, ZSTD, Delta, T64) typically reach 10–100Γ— compression on real data.

It is not a transactional database. There is no row-level UPDATE/DELETE in the traditional sense, no foreign keys, no MVCC. It excels at append-mostly analytical workloads.


2. Storage architecture

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Storage architecture".

Here is a brief excerpt from the material I'm reading:

"""
### Files inside one part β€” what each is for | File                              | Purpose                                                                | | `<column>.bin`                    | The column's compressed data, in granule order.                        | | `<column>.mrk2` (or `.mrk`)       | Marks: byte offset into `.bin` for each granule (so reads can seek).   | | `primary.idx`                     | Sparse primary key β€” one row per granule.                              | | `count.txt`                       | Cached row count of this part.                                         |
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         ClickHouse Server                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                    β”‚                       β”‚
        β–Ό                    β–Ό                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  HTTP :8123  β”‚    β”‚   TCP :9000    β”‚    β”‚  Inter-server :9009 β”‚
β”‚  (REST/JSON) β”‚    β”‚ (native binary)β”‚    β”‚  (replica fetches)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                    β”‚                       β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚ Query Pipeline β”‚  parser β†’ analyzer β†’ planner β†’
                    β”‚                β”‚  pipeline β†’ vectorised execution
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                             β–Ό
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚  Storage Layer β”‚
                    β”‚   (MergeTree)  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό                    β–Ό                    β–Ό
   /var/lib/clickhouse/  /var/lib/clickhouse/  /var/lib/clickhouse/
   data/<db>/<table>/    metadata/<db>/        store/<...uuid>/
   β”œβ”€ <part_name>/       β”œβ”€ <table>.sql        (atomic-engine table data)
   β”‚  β”œβ”€ columns.txt     └─ <table>.sql.bak
   β”‚  β”œβ”€ checksums.txt
   β”‚  β”œβ”€ count.txt
   β”‚  β”œβ”€ default_compression_codec.txt
   β”‚  β”œβ”€ minmax_<col>.idx (per partition column)
   β”‚  β”œβ”€ partition.dat
   β”‚  β”œβ”€ primary.idx     ← sparse PK (one entry per granule)
   β”‚  β”œβ”€ <col>.bin       ← column data, compressed
   β”‚  └─ <col>.mrk2      ← marks: offsets into <col>.bin
   β”œβ”€ <part_name>/
   └─ ...

Files inside one part β€” what each is for

File Purpose
<column>.bin The column's compressed data, in granule order.
<column>.mrk2 (or .mrk) Marks: byte offset into .bin for each granule (so reads can seek).
primary.idx Sparse primary key β€” one row per granule.
count.txt Cached row count of this part.
columns.txt Column-name β†’ type mapping for this part.
checksums.txt SHA1 of every other file. Reads against this to detect corruption.
default_compression_codec.txt Codec used for any column that didn't specify one.
minmax_<col>.idx Min/max of partition columns β€” partition-pruning input.
partition.dat Serialized partition value (e.g. 202601).

3. The MergeTree engine

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "The MergeTree engine".

Here is a brief excerpt from the material I'm reading:

"""
`MergeTree` is *the* default table engine. Everything that does replication, deduplication, TTL, or sharding is a variant of it. ### Required + optional clauses ### How `ORDER BY` interacts with `PRIMARY KEY` - `ORDER BY` is required and defines **on-disk sort order**. - `PRIMARY KEY` is the **sparse index**. If omitted (the common case), it equals `ORDER BY`. If specified, **it must be a prefix of ORDER BY**. - Common pattern: `PRIMARY KEY (a, b)` + `ORDER BY (a, b, c, d)` β€” the index is small (only `a, b` go into `primary.idx`) but rows are fully sorted, so `c, d` filters still get sequentia...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

MergeTree is the default table engine. Everything that does replication, deduplication, TTL, or sharding is a variant of it.

Required + optional clauses

CREATE TABLE events (
    event_time  DateTime,
    user_id     UInt32,
    revenue     Float64
)
ENGINE = MergeTree
ORDER BY (event_time, user_id)        -- 1. defines on-disk sort + default PK
PARTITION BY toYYYYMM(event_time)     -- 2. optional. keeps related rows together
PRIMARY KEY (event_time)              -- 3. optional. must be PREFIX of ORDER BY
SAMPLE BY intHash32(user_id)          -- 4. optional. enables SAMPLE clause
TTL event_time + INTERVAL 90 DAY      -- 5. optional. auto-delete or move
SETTINGS
    index_granularity = 8192,         -- rows per mark (default)
    min_rows_for_wide_part = 10000000;

How ORDER BY interacts with PRIMARY KEY

index_granularity = 8192

                     β”Œβ”€β”€β”€β”€β”€ granule 0 (8192 rows) ─────┐
                     β”‚                                  β”‚
events.event_time:   2026-01-01 00:00:00 ...  2026-01-01 09:23:11
events.user_id:      4321 ............................. 9087
                     β–²
                     β”‚  one entry in primary.idx points here:
                     β”‚     (2026-01-01 00:00:00, 4321)
                     β”‚
                     β”Œβ”€β”€β”€β”€β”€ granule 1 (8192 rows) ─────┐
                     β”‚                                  β”‚
                     2026-01-01 09:23:11 ...  2026-01-01 18:42:55

A WHERE event_time BETWEEN '2026-01-01 06:00' AND '2026-01-01 12:00' query reads primary.idx, finds only the granules that could contain matching rows, and reads just those <col>.bin byte ranges. A 2-billion-row scan becomes a 100K-row scan.


4. Parts, partitions, merges

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Parts, partitions, merges".

Here is a brief excerpt from the material I'm reading:

"""
A **part** is an immutable directory under `/var/lib/clickhouse/data/<db>/<table>/`. Every `INSERT` produces a new part. Background workers later **merge** small parts into bigger ones, sorted by the table's `ORDER BY`. This is the engine's name. ### Decoding a part name If the table has `PARTITION BY toYYYYMM(...)`, parts look like `202601_5_5_0` instead β€” partition `202601`, blocks 5..5, level 0. ### Why merges matter - Without merges: one tiny part per insert β†’ millions of small files β†’ the file system and the engine both choke. - With merges: a logarithmic number of parts; reads stream seq...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

A part is an immutable directory under /var/lib/clickhouse/data/<db>/<table>/. Every INSERT produces a new part. Background workers later merge small parts into bigger ones, sorted by the table's ORDER BY. This is the engine's name.

INSERT 1 ──► all_1_1_0/   (rows 1..500k)
INSERT 2 ──► all_2_2_0/   (rows 500k..1M)
INSERT 3 ──► all_3_3_0/   (rows 1M..2M)

   background merge ─────────────► all_1_3_1/   (rows 1..2M, sorted)

   later, the originals are removed:
                                 β”‚
                                 β–Ό
                        active parts:  all_1_3_1/
                        inactive parts: all_1_1_0/, all_2_2_0/, all_3_3_0/  (deleted soon)

Decoding a part name

        all_  1_3_1
        ─┬─   ─┬───
         β”‚     β”‚  └── merge level (0 = freshly inserted, 1 = 1st merge, …)
         β”‚     β”‚
         β”‚     └── min_block..max_block of source parts
         β”‚
         └── partition (here, all rows in one partition called 'all')

If the table has PARTITION BY toYYYYMM(...), parts look like 202601_5_5_0 instead β€” partition 202601, blocks 5..5, level 0.

Why merges matter

Partitions β‰  shards

A partition is a logical group of parts within one node (one directory tree per partition value). A shard is a whole node in a cluster. Use partitioning to drop old data cheaply (DROP PARTITION) and to bound merge work; use sharding to spread data across machines.

Rule of thumb: partition by month for most workloads. Day-partitioning is for very high-throughput tables (>1B rows/day). Year-partitioning is for cold archival. Anything more granular than the access pattern is counterproductive β€” too many partitions = slow merges + metadata bloat.


5. Compression and codecs

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Compression and codecs".

Here is a brief excerpt from the material I'm reading:

"""
Every column is compressed independently. Codecs can be **stacked**. | Codec                   | Best for                                                              | | `LZ4` (default)         | Anything; very fast, ~2Γ— compression on text, more on integers.       | | `ZSTD(level)`           | Larger compression than LZ4 (~30–50% smaller), slower. Levels 1–22.   | | `Delta(N)`              | Monotonic series (timestamps, counters). Stores differences.          | | `DoubleDelta`           | Timestamps with regular intervals (e.g. metrics every 1s).            | | `Gorilla`               | Flo...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

Every column is compressed independently. Codecs can be stacked.

CREATE TABLE metrics (
    ts        DateTime CODEC(Delta(4), LZ4),    -- delta-of-delta, then LZ4
    cpu       UInt32   CODEC(T64, LZ4),         -- bit-pack, then LZ4
    rps       UInt64   CODEC(T64, ZSTD(3)),     -- bit-pack, then ZSTD level 3
    label     String   CODEC(ZSTD(6))           -- ZSTD level 6 for text
)
ENGINE = MergeTree ORDER BY ts;
Codec Best for
LZ4 (default) Anything; very fast, ~2Γ— compression on text, more on integers.
ZSTD(level) Larger compression than LZ4 (~30–50% smaller), slower. Levels 1–22.
Delta(N) Monotonic series (timestamps, counters). Stores differences.
DoubleDelta Timestamps with regular intervals (e.g. metrics every 1s).
Gorilla Float time-series (Facebook's Gorilla algorithm).
T64 Integer columns where most values fit in fewer bits than the type.
LowCardinality(T) Not a codec β€” a type wrapper for high-repetition strings.

The demo's extras.sql shows the actual ratios on identical data: Delta + LZ4 reaches 0.5 % of raw on a monotonic timestamp column (199Γ— compression).


6. TTL β€” automatic data lifecycle

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "TTL β€” automatic data lifecycle".

Here is a brief excerpt from the material I'm reading:

"""
Three flavours, all expressed on a date/time column: TTL runs **at merge time** in the background. It's not instant; for the demo we use `merge_with_ttl_timeout = 60` so the next `OPTIMIZE` actually purges old rows.
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

Three flavours, all expressed on a date/time column:

-- Whole-row TTL: delete rows after 90 days
ENGINE = MergeTree
ORDER BY (...)
TTL event_time + INTERVAL 90 DAY DELETE;

-- Column-level TTL: drop the column, keep the row
ENGINE = MergeTree ORDER BY (...)
( ...
    payload String TTL event_time + INTERVAL 30 DAY,
    ...);

-- Move-to-cold-disk TTL (with a multi-disk storage policy):
TTL event_time + INTERVAL 30 DAY TO VOLUME 'cold',
    event_time + INTERVAL 1 YEAR DELETE;

TTL runs at merge time in the background. It's not instant; for the demo we use merge_with_ttl_timeout = 60 so the next OPTIMIZE actually purges old rows.


7. The system.* tables you'll live in

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "The system.* tables you'll live in".

Here is a brief excerpt from the material I'm reading:

"""
(no excerpt β€” section heading was "The system.* tables you'll live in")
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

These are CH's introspection surface. Memorise the shape of each.

Table Use when…
system.tables "What's the schema, ORDER BY, partition key?"
system.parts "How many parts? Active vs inactive? Sizes? Compressed/uncompressed?"
system.parts_columns Per-column sizes within each part.
system.columns Schema-level column info: type, codec, default expression.
system.merges Currently-running merges. Empty when idle.
system.mutations ALTER UPDATE/DELETE jobs. They run async.
system.query_log One row per finished query: duration, rows read, memory.
system.query_thread_log Per-thread breakdown of each query.
system.events Lifetime counters: InsertedRows, MergedRows, etc.
system.metrics Current values: connections, queued queries.
system.asynchronous_metrics Sampled gauges: cache size, FS free.
system.processes Currently-running queries (the SHOW PROCESSLIST equivalent).
system.settings Every server/session setting and its current value.
system.disks / system.storage_policies Multi-disk configuration.

SYSTEM FLUSH LOGS; forces the buffered logs to disk so the next SELECT finds them.


8. The hands-on demo

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "The hands-on demo".

Here is a brief excerpt from the material I'm reading:

"""
### What you get ### Run `./run.sh` self-bootstraps β€” if the container isn't up, it calls `up.sh`. ### Execution flow β€” what runs, in order | #  | Step                                | What happens                                                                                                                                                  | | 0  | self-bootstrap                      | If `m1-clickhouse` isn't responding to `/ping`, the script calls `up.sh` first. `up.sh` tears down any other demo module that's holding port 8123, then `docker compose up -d`. | | 1  | `setup.sql`...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

What you get

docker-compose.yml          m1-clickhouse Β· ports 8123/9000
configs/clickhouse-config.xml
setup.sql Β· data.sql Β· queries.sql Β· extras.sql
up.sh Β· run.sh Β· down.sh

Run

./up.sh        # docker compose up -d, waits for /ping
./run.sh       # creates DB, inserts ~2M rows, runs demo queries
./down.sh      # docker compose down -v  (drops volumes)

./run.sh self-bootstraps β€” if the container isn't up, it calls up.sh.

Execution flow β€” what runs, in order

# Step What happens
0 self-bootstrap If m1-clickhouse isn't responding to /ping, the script calls up.sh first. up.sh tears down any other demo module that's holding port 8123, then docker compose up -d.
1 setup.sql Creates database m1 and one MergeTree table m1.events partitioned by month, ordered by (event_time, user_id), default index_granularity = 8192.
2 data.sql (~2M rows in 3 inserts) Three INSERT … SELECT FROM numbers(...) (500k + 500k + 1M). Three on purpose: leaves three active parts so merges have something to do.
3 queries.sql Eight observation queries: row count, system.parts, partitions/sizes, PK vs sorting key, OPTIMIZE FINAL, post-merge part count, date-range aggregation, and SYSTEM FLUSH LOGS + system.query_log to see how many rows the previous SELECT actually read.
4 extras.sql Curriculum extras: TTL table, codec-comparison table (Delta, T64, ZSTD(3) vs LZ4), complex-types table (Enum, Nullable, Array, Tuple, Map, Nested), DESCRIBE TABLE, SHOW CREATE TABLE.
5 HTTP API smoke test wget -qO- 'http://localhost:8123/?query=SELECT count() FROM m1.events' from inside the container β€” should return 2000000.

What to look for

Step What you should see
3 sequential INSERTs 3 active parts in system.parts initially.
Partition by toYYYYMM Parts grouped under 202601, 202602, 202603.
OPTIMIZE TABLE … FINAL Active part count drops; bytes per part rise.
system.tables primary_key and sorting_key both event_time, user_id.
Codec comparison Delta(4)+LZ4 β‰ˆ 0.5 % of raw on monotonic timestamps; T64+LZ4 β‰ˆ 3 % of raw on monotonic UInt64.
Date-range query read_rows in query_log is much less than 2M β€” proof that PK pruning works.

9. Configuration reference (the demo's config)

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Configuration reference (the demo's config)".

Here is a brief excerpt from the material I'm reading:

"""
`configs/clickhouse-config.xml` is bind-mounted into the container under `/etc/clickhouse-server/config.d/00-custom.xml`. CH layers `config.d/` files on top of the base `config.xml`. > **Important on CH 26.x**: user-level settings (`max_memory_usage`, > `max_rows_to_read`, etc.) cannot live at the top level of `config.xml` > any more β€” they belong in `users.d/<file>.xml` under > `<profiles><default>...</default></profiles>`. Putting them at the top > level used to work; on 26.4+ the server refuses to start.
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

configs/clickhouse-config.xml is bind-mounted into the container under /etc/clickhouse-server/config.d/00-custom.xml. CH layers config.d/ files on top of the base config.xml.

<clickhouse>
    <logger>
        <level>notice</level>
        <log>/var/log/clickhouse-server/clickhouse-server.log</log>
        <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
        <size>1000M</size><count>10</count>
    </logger>

    <!-- Persistent system logs: one row per query/part/merge. Without
         these, system.query_log and friends are empty after restart. -->
    <query_log><database>system</database><table>query_log</table></query_log>
    <query_thread_log><database>system</database><table>query_thread_log</table></query_thread_log>
    <part_log><database>system</database><table>part_log</table></part_log>

    <listen_host>0.0.0.0</listen_host>     <!-- accept TCP from anywhere -->
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <interserver_http_port>9009</interserver_http_port>

    <max_connections>4096</max_connections>
    <background_pool_size>16</background_pool_size>          <!-- merge workers -->
    <background_schedule_pool_size>16</background_schedule_pool_size>

    <path>/var/lib/clickhouse/</path>
    <tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
    <user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
</clickhouse>

Important on CH 26.x: user-level settings (max_memory_usage, max_rows_to_read, etc.) cannot live at the top level of config.xml any more β€” they belong in users.d/<file>.xml under <profiles><default>...</default></profiles>. Putting them at the top level used to work; on 26.4+ the server refuses to start.


10. Common pitfalls

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Common pitfalls".

Here is a brief excerpt from the material I'm reading:

"""
| Symptom                                                      | Cause                                                                | Fix                                                                                       | | Inserts get progressively slower; CPU spent in merges        | Many small inserts β†’ too many parts.                                 | Batch inserts (1k–100k rows). Use Buffer engine *only* if you can't.                      | | `Too many parts (N). Merges are processing significantly slower than inserts` | Same as above, but now hard-failing.                | Slow dow...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.
Symptom Cause Fix
Inserts get progressively slower; CPU spent in merges Many small inserts β†’ too many parts. Batch inserts (1k–100k rows). Use Buffer engine only if you can't.
Too many parts (N). Merges are processing significantly slower than inserts Same as above, but now hard-failing. Slow down inserts; raise parts_to_throw_insert only as a temporary lifeline.
Tiny query reads millions of rows PK doesn't cover the filter; or filter isn't on a PK-prefix column. Re-shape ORDER BY, or add a skip-index/projection (Module 6).
Memory limit exceeded Aggregation needs more than max_memory_usage (default 10 GB). Raise the limit, or use max_bytes_before_external_group_by to spill to disk.
Code: 60. Unknown table 'system.query_log' First SELECT on query_log arrives before its periodic flush. SYSTEM FLUSH LOGS; before the SELECT.
INSERT VALUES hangs forever via clickhouse-client --multiquery --query "..." + open stdin β†’ CH waits for more data. Pipe the SQL via printf %s "$SQL" | clickhouse-client (this demo does that already).

11. Talking points for the live session

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Talking points for the live session".

Here is a brief excerpt from the material I'm reading:

"""
1. **Why columnar?** Walk through "SELECT avg(revenue) FROM events WHERE country = 'US'": only 2 columns are read; rows are processed in batches; the entire query touches ~kilobytes of memory. 2. **Why merges?** Show `system.merges` mid-INSERT β€” there's almost always a background job running. 3. **Sorting key vs primary key.** Most tables use only `ORDER BY` and let the PK equal it. The split is a tuning knob for the rare case where ORDER BY has high-cardinality trailing columns you don't want in the index. 4. **`index_granularity = 8192`** is why the PK is tiny. Demonstrate by showing `primar...
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.
  1. Why columnar? Walk through "SELECT avg(revenue) FROM events WHERE country = 'US'": only 2 columns are read; rows are processed in batches; the entire query touches ~kilobytes of memory.
  2. Why merges? Show system.merges mid-INSERT β€” there's almost always a background job running.
  3. Sorting key vs primary key. Most tables use only ORDER BY and let the PK equal it. The split is a tuning knob for the rare case where ORDER BY has high-cardinality trailing columns you don't want in the index.
  4. index_granularity = 8192 is why the PK is tiny. Demonstrate by showing primary.idx size vs row count.
  5. OPTIMIZE FINAL is a debugging convenience. Never run it from cron β€” it'll take down a busy server.
  6. Append-only mindset. Every INSERT writes a fresh part. Conventional "UPDATE" is done via Replacing/Collapsing engines (Module 2) or ALTER TABLE … UPDATE (which writes an async mutation, not an UPDATE).

12. Container ports

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Container ports".

Here is a brief excerpt from the material I'm reading:

"""
| Service        | Container port | Host port | | HTTP           | 8123           | 8123      | | Native (TCP)   | 9000           | 9000      | | Inter-server   | 9009           | (not exposed; cluster-only) | The default user is loopback-only when no `CLICKHOUSE_PASSWORD` is set, so the demo's HTTP smoke test runs `wget` from *inside* the container. Production: define users in `users.d/` (Module 5 walks through this).
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.
Service Container port Host port
HTTP 8123 8123
Native (TCP) 9000 9000
Inter-server 9009 (not exposed; cluster-only)

The default user is loopback-only when no CLICKHOUSE_PASSWORD is set, so the demo's HTTP smoke test runs wget from inside the container. Production: define users in users.d/ (Module 5 walks through this).


13. Going deeper

πŸ’¬ Discuss with AI β€” click to view prompt
Paste into ChatGPT, Claude, Gemini, or any LLM chat.
I'm studying ClickHouse and working through the module "ClickHouse Fundamentals". I want to deeply understand the section: "Going deeper".

Here is a brief excerpt from the material I'm reading:

"""
- **Module 2** β€” every `*MergeTree` variant in detail. - **Module 6** β€” the same primary-key/projection knobs, with measured query timings on 60M rows. - **ClickHouse docs** β€” <https://clickhouse.com/docs> (especially the MergeTree, Codecs, and System Tables sections). When you're comfortable with this module, tear down (`./down.sh`) and move to Module 2.
"""

Please explain this concept in depth. Cover:

1. **Core mechanics** β€” how does it actually work under the hood? What data structures, algorithms, or engine internals are involved? Where is the implementation in the ClickHouse source tree (file/folder names) if you know?

2. **When to use vs avoid** β€” what concrete workloads does this help, and when would it hurt or be wrong? Give specific scale/latency trade-offs.

3. **Comparable features in other systems** β€” how does this compare with similar features in PostgreSQL, MySQL, BigQuery, Snowflake, Redshift, or DuckDB? Build my intuition by analogy.

4. **Common pitfalls and gotchas** β€” what trips engineers up in production? Subtle bugs, performance traps, surprising semantics?

5. **Worked example** β€” show me a small but realistic SQL or config example that demonstrates the concept end-to-end. Include the expected output where useful.

6. **Where to read more** β€” a short list of authoritative pointers (CH docs, blog posts, talks, source-code files).

Assume I have solid SQL fundamentals but I'm new to ClickHouse internals. Be technical but pragmatic; avoid marketing language.

When you're comfortable with this module, tear down (./down.sh) and move to Module 2.

πŸ“Š ClickHouse Knowledge Transfer

Module 1 of 10 | Duration: 6-8 weeks total

Created for comprehensive ClickHouse training | 2026

← Previous Module 🏠 Home Next: Module 2 - Table Engines β†’