Columnar storage doesn't just mean "read fewer columns" — it also compresses dramatically better than row storage, because every value sitting next to another value on disk is now the same type of thing: a column of country codes next to more country codes, a column of timestamps next to more timestamps. Similar values compress far better than a shuffled row of unrelated types ever could.
Two layers of compression, per column
Each column's data passes through an optional specialized encoding, then a general-purpose compressor. Both are configurable per column.
one column's write path
Raw columne.g. timestamps
CodecDelta / DoubleDelta / Gorilla
Compressed blockwritten to the part
CompressorLZ4 (default) / ZSTD
Specialized codecs exploit structure the compressor can't see
Delta— stores the difference between consecutive values. Great for slowly-increasing IDs or timestamps, where the deltas are much smaller numbers than the values themselves.DoubleDelta— deltas of deltas. Even better for near-constant-interval timestamps.Gorilla— designed for floating-point time-series (metrics) where consecutive values are close together.T64— transposes bits of fixed-width integers to expose more redundancy before general compression.
General compressors trade speed for ratio
LZ4(default) — very fast to decompress, which matters more than raw ratio for most analytical queries that decompress a column, use it, and move on.ZSTD— noticeably better compression ratio, more CPU per read. Common choice for cold/rarely-queried data or when storage cost dominates.
CREATE TABLE metrics
(
ts DateTime CODEC(DoubleDelta, ZSTD),
value Float64 CODEC(Gorilla, ZSTD),
host LowCardinality(String) CODEC(ZSTD)
)
ENGINE = MergeTree
ORDER BY ts;Why it exists
LowCardinality(String) isn't a compression codec, but it belongs in the same conversation: it dictionary-encodes a string column (storing small integer IDs instead of repeated text), which shrinks both storage and the amount of data the query engine has to touch — a huge win for columns like country, status, or event type.Production note
Sort order affects compression too: a column that is the second or third key in
ORDER BY tends to have long runs of repeated or near-sequential values within each granule, which is exactly what these codecs are built to exploit. Good schema design (primary key) and good compression are not separate problems.