Free — no signup required

Row vs. Columnar Storage

2 min read

How the Bytes Lay on Disk

Traditional databases (like PostgreSQL or MySQL) are Row-Oriented. If you have a Users table, all the data for User A is written sequentially on disk, followed by all the data for User B. The physical layout mirrors the logical table structure.

Disk layout (row-oriented):
[UserA: id=1, name="Alice", country="USA", age=30, email="[email protected]"]
[UserB: id=2, name="Bob",   country="Canada", age=25, email="[email protected]"]
[UserC: id=3, name="Carol", country="USA", age=35, email="[email protected]"]

Pro: Great for transactional workloads (OLTP). If you need to fetch "everything about user 123," the disk head jumps to one location and reads the whole record in a single sequential operation. Inserts and updates are also efficient because all fields for a row are co-located.

Con: Terrible for analytical queries that touch only a few columns across many rows.

The Analytics Problem

Imagine you have a billion users and you want to run: SELECT AVG(age) FROM Users;

In a row-oriented database, the engine must read every single full row just to extract the age value. It reads terabytes of names, email addresses, and country codes — then immediately discards them. On a 10-column table, you're doing 10x more I/O than necessary. On a 100-column table, 100x more. This is the fundamental inefficiency of row storage for analytical workloads.

The Solution: Columnar Storage

In Columnar Storage, data is grouped by column on disk. All age values are stored together. All name values are stored together.

Disk layout (columnar):
[id column:      1, 2, 3, ...]
[name column:    "Alice", "Bob", "Carol", ...]
[country column: "USA", "Canada", "USA", ...]
[age column:     30, 25, 35, ...]
[email column:   "alice@...", "bob@...", "carol@...", ...]

Pro: Great for analytics (OLAP). The AVG(age) query reads only the age column from disk. The other four columns are never touched. I/O drops by 80% on a 5-column table.

Con: Terrible for OLTP. Fetching a single complete row requires reading from five separate locations on disk — one per column. Inserts are also more complex because each field must be written to a different location.

This is why modern data architectures separate OLTP (row-oriented RDBMS) from OLAP (columnar data warehouse or data lake). They are physically optimized for different access patterns.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free