Chapter 03 · Storage & Retrieval
The world's simplest database is two lines of bash. Here's why it fails, and what replaces it.
Writes are easy. Reads without an index aren't. Every storage engine is a different bet on which one you'd rather pay for.
Three acts: 1. log 2. engine 3. workload
Bitcask in ~40 lines: append writes, index reads.
Writes append. Reads seek by hash. Works until the index outgrows RAM, or you need a range scan.
B-tree · LSM-tree · how LSM stays fast.
Takeaway
LSM-trees turn random writes into sequential ones. That's the whole trick.
Same rows, two physical layouts. Same data, opposite workloads.
OLTP · fetch full rows.
OLAP · scan few columns of many rows.
── Reference ──
Three engines · two layouts · five things to remember.
| Engine | Best for | Read cost | Write cost | Space | Examples |
|---|---|---|---|---|---|
| Hash index | Point lookups, small keyspace | O(1) if index in RAM; disk seek on miss | O(1) append + index update | Whole index must fit in RAM | Bitcask, Riak's Bitcask backend |
| B-tree | Balanced OLTP | O(log n) disk seeks | O(log n) + WAL fsync | Fragmentation, ~70% fill factor | PostgreSQL, MySQL/InnoDB, SQL Server |
| LSM-tree | Write-heavy; range scans | O(log n) across levels; bloom filters help | O(1) memtable append; batched flush | Write amplification 5–30× before compaction | RocksDB, LevelDB, Cassandra, HBase |
| Row-oriented | Column-oriented | |
|---|---|---|
| Layout | Whole row contiguous on disk | One column across many rows contiguous |
| Best for | OLTP: fetch a whole record | OLAP: aggregate over one column |
| Compression | Low (heterogeneous types adjacent) | High (values in a column repeat) |
| Write pattern | Update one row, touch one page | Update one row, touch many files (usually rewritten in bulk) |
| Examples | PostgreSQL, MySQL, MongoDB | Parquet, ORC, Vertica, Redshift, BigQuery |
Hash index → point lookups only; whole index in RAM.
B-tree → in-place updates; balanced tree; random I/O.
LSM-tree → append-only; sequential writes; background compaction.
Row-oriented → OLTP: one whole record at a time.
Column-oriented → OLAP: one column across many records.