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.