Exploring Schema Optimization and Compression in ClickHouse
Big Data
5 MIN READ
August 11, 2026
A ClickHouse table with the wrong data types can quietly cost you 3 to 5 times more disk space than it needs to, and that extra I/O shows up directly in query latency. The fix usually isn’t more hardware. It’s picking the right column type and compression codec for each field before you load a single row.
To see exactly how much this matters, we built two versions of the same 1,000,000-row event log table: one using ClickHouse’s default types, and one applying Enum8, LowCardinality, specialized codecs, and HyperLogLog. Below are the exact storage numbers, what broke along the way, and the settings that mattered most.
ClickHouse Storage Internals: How Compression Choices Cut Disk Usage by 3 to 5x
ClickHouse’s query speed doesn’t come only from reading data in columns. It comes from how aggressively it compresses those columns once they’re on disk. Pick the wrong data type or skip the right compression codec, and the same table can end up 3 to 5 times larger than it needs to be, with every extra byte adding to the I/O your queries have to push through.
To see exactly where that difference comes from, I built benchmark tables using several data schemas, comparing standard types against optimizations like Enum8, LowCardinality, specialized codecs, arrays, and HyperLogLog (AggregateFunction). Below are the practical observations and the exact storage numbers from that comparison.
Similar schema-design tradeoffs show up across most big data consulting engagements, since the right column types and codecs one team picks rarely transfer cleanly to another team’s workload.
Concepts Explored
Concept
What It Means
Enum8 vs. LowCardinality
Choosing between static, hardcoded string alternatives versus dynamic dictionary encoding for low-cardinality textual data.
Specialized Compression Codecs
Moving beyond standard LZ4 to leverage specialized algorithms like DoubleDelta, Gorilla, and ZSTD.
Array Column Mechanics
How ClickHouse internally separates array sizes from flat data blocks on disk.
HyperLogLog (HLL) Approximations
Saving massive amounts of storage by using probabilistic data structures instead of storing unique raw strings.
Compression Metrics Comparison
Tracking the explicit storage footprints of each optimization inside the system views.
Practical Hands-on
I created a benchmarking table events_naive to test standard data types, alongside an optimized version events_optimized. I loaded both with exactly 10,00,000 rows of identical simulated event log data.
Here is the unoptimized baseline schema:
CREATE TABLE default.events_naive
(
event_id UInt64,
status String, -- Repeated values ('success', 'failed', 'pending')
city String, -- Semi-repeated values (approx 50 unique cities)
metric_value Float64, -- Slow-changing time-series float values
user_tags Array(String)
)
ENGINE = MergeTree
ORDER BY event_id;
Ready to Cut Your ClickHouse Storage Costs?
And here is the heavily optimized schema applying specialized types and compression structures:
CREATE TABLE default.events_optimized
(
event_id UInt64 CODEC(DoubleDelta, LZ4),
status Enum8('success' = 1, 'failed' = 2, 'pending' = 3),
city LowCardinality(String),
metric_value Float64 CODEC(Gorilla, ZSTD),
user_tags Array(String)
)
ENGINE = MergeTree
ORDER BY event_id;
Storage Footprint Comparison (Visual Proof)
After running the batch inserts, I queried the system.columns table to see the precise number of bytes each column consumed on the disk.
SELECT
column,
type,
data_compressed_bytes,
data_uncompressed_bytes,
round(data_uncompressed_bytes / data_compressed_bytes, 2) AS compression_ratio
FROM system.columns
WHERE table IN ('events_naive', 'events_optimized')
ORDER BY column ASC;
Column Name
Unoptimized Type (events_naive Size)
Optimized Type (events_optimized Size)
Savings / Observation
event_id
UInt64 (Standard LZ4) → 4.2 MB
UInt64 CODEC(DoubleDelta, LZ4) → 820 KB
~80% savings (DoubleDelta stores differences instead of raw numbers)
status
String → 5.1 MB
Enum8 → 980 KB
Stores values as 1-byte integers internally
city
String → 14.8 MB
LowCardinality(String) → 2.1 MB
Creates an automatic dynamic dictionary mapping
metric_value
Float64 → 7.8 MB
Float64 CODEC(Gorilla, ZSTD) → 3.4 MB
Gorilla compresses floating points by XORing consecutive bits
These aren’t just synthetic gains – this real-world ad-tech clickstream rebuild on ClickHouse cut ingestion lag by 97% using many of the same schema optimizations.
Need Expert Help Optimizing Your ClickHouse Schema?
While testing LowCardinality(String) on the city column, it worked beautifully because there were only around 50 unique cities. However, when I tried applying LowCardinality to a high-cardinality column like user_id (with over 800,000 unique values), the table size actually increased, and search performance degraded. ClickHouse had to build a massive, inefficient dictionary overhead file in the background.
The Mechanics of Array Columns
When exploring the data directory under ./data/default/events_optimized/, I noticed that for the user_tags column, ClickHouse generated two separate physical files: user_tags.bin (storing raw strings flattened out) and a user_tags.mrk2 / sizes file. This proved why nested or large array structures can cause heavy disk seeks if arrays are deeply layered.
HyperLogLog (HLL) Cardinality Savings
To count unique users without storing heavy strings, I experimented with the HyperLogLog probabilistic structure:
-- Storing raw strings for unique counting vs HLL state
CREATE TABLE default.hll_test (
user_set AggregateFunction(uniqCombined(14), String)
) ENGINE = MergeTree ORDER BY tuple();
Storing raw user strings for exact counting took nearly 80 MB for a test run. Using uniqCombined (HLL state) dropped the storage footprint to under 3 MB while maintaining an error rate below 1% across the benchmark datasets.
Check how a similar tiered-storage strategy helped a telecom client cut ClickHouse storage costs by 40% in this case study.
Key Learnings
Enum8 is for Static Sets, LowCardinality is for Dynamic Sets: Use Enum8 when values are fixed and unlikely to change (e.g., status codes). Use LowCardinality when strings are repeated but can grow over time, keeping unique values well under 10,000.
Codecs Outperform Plain Compression: Never settle for default LZ4 on sequential keys or time-series metrics. Combining DoubleDelta for monotonically increasing IDs or Gorilla for smooth floating-point values significantly reduces disk usage and accelerates query execution speed.
Trade Accuracy for Scale with HLL: For massive dashboards where trend analysis matters more than exact counts, storing data as HLL states via AggregateFunction(uniqCombined, ...) saves vast amounts of storage and eliminates heavy in-memory distinct counts.
Benchmarking schema choices on a single table is one thing; keeping codec strategy, LowCardinality dictionaries, and merge behavior consistent across a sharded, multi-replica ClickHouse cluster under real write load is another. That’s the gap most teams hit once ClickHouse moves from a proof of concept to a production analytics platform.
Ksolves provides ClickHouse consulting and 24×7 enterprise support: cluster setup, schema and compression audits, performance tuning, and migration support for teams running ClickHouse at scale. If storage costs or query latency are creeping up, explore our ClickHouse support services.
Anil Kushwaha, Technology Head at Ksolves, is an expert in Big Data. With over 11 years at Ksolves, he has been pivotal in driving innovative, high-volume data solutions with technologies like Nifi, Cassandra, Spark, Hadoop, etc. Passionate about advancing tech, he ensures smooth data warehousing for client success through tailored, cutting-edge strategies.
Fill out the form below to gain instant access to our exclusive webinar. Learn from industry experts, discover the latest trends, and gain actionable insights—all at your convenience.
AUTHOR
Big Data
Anil Kushwaha, Technology Head at Ksolves, is an expert in Big Data. With over 11 years at Ksolves, he has been pivotal in driving innovative, high-volume data solutions with technologies like Nifi, Cassandra, Spark, Hadoop, etc. Passionate about advancing tech, he ensures smooth data warehousing for client success through tailored, cutting-edge strategies.
Share with