Compression — the column store's superpower
When adjacent bytes are the same column they are the same type and often the same or similar values, so run-length encoding and dictionary encoding deliver 5-20x compression that fails completely on row pages — and the encoded form is what the executor reads.
Once adjacent bytes are the same column, compression that fails on row pages suddenly works — and the win is per-column, not generic gzip.
Scene 03
Compression: the column store's superpower
- Watch
- Try it
- Predict
- Capture
country.bin streams in — 20 rows of a low-cardinality string column (US, DE, JP). The byte counter top-right tracks the cost of the raw layout: 2 bytes per row, 40 bytes total. Notice how adjacent rows often share the same value — that's the property the next mode will exploit.
Highlighted lines are the ones running in the diagram right now.
def rle_encode(values):runs = []for v in values:last = runs[-1] if runs else Noneif last and last.value == v:last.run += 1 # extend current runelse:runs.append(Run(value=v, run=1))return runs # on-disk form for RLE columns
def count_where(col, target):if col.mode == RAW:return sum(1 for v in col.values if v == target)if col.mode == RLE:# no decompression — sum run lengths of matching runsreturn sum(r.run for r in col.runs if r.value == target)if col.mode == DICT:code = col.dictionary.codeFor(target) # 'US' -> 2return sum(1 for c in col.codes if c == code)
def dict_encode(values):dictionary = {} # value -> small int codecodes = []for v in values:if v not in dictionary:dictionary[v] = len(dictionary) # next codecodes.append(dictionary[v])# cardinality check — the LowCardinality(String) trap# fires when len(dictionary) approaches len(values).return codes, dictionary
Where this sits in Build a columnar OLAP store (ClickHouse / Druid style)
Scene 03 of 13, in the Speedups act — Compression and vectorized execution — where the orders of magnitude live.. Adjacent column values are same-type and often similar, so RLE and dictionary encoding deliver 5–20× shrinkage that fails completely on row pages.
Up next. The bytes on disk are now tiny. But pulling tiny bytes through the CPU one row at a time still leaves a 50x performance win on the table — it depends on how the executor walks those bytes.
All 13 scenes in Build a columnar OLAP store (ClickHouse / Druid style) · Every curriculum