Skip to content

Storage & Warehousing

  • Storage engine choice is about access pattern: LSM-trees for write-heavy, B-trees for read/update-heavy, columnar for scan-heavy analytics
  • The data lake (cheap raw storage) and data warehouse (structured, queryable) are converging into the lakehouse via open table formats
  • Partitioning and clustering are the highest-leverage performance levers in any warehouse — prune data before you scan it
  • Table formats (Iceberg, Delta, Hudi) bring ACID transactions, time travel, and schema evolution to files on object storage
  • Load the same dataset into Parquet-on-object-storage and a warehouse; compare query cost and speed
  • Build a star schema for a toy domain (e.g. retail orders) by hand — facts, dimensions, grain
  • Read DDIA Ch 3 to understand why LSM-trees and B-trees behave differently under load

Where and how you lay data on disk determines everything downstream: a write-optimized engine makes analytics crawl, and a scan-optimized layout makes single-row updates painful. The art is matching the physical layout (row vs column, indexed vs partitioned, mutable vs append-only) to the dominant access pattern, then letting open table formats give you warehouse guarantees on cheap lake storage.

DDIA Ch 3

Key ideas:

  • LSM-trees (log-structured merge): buffer writes in memory, flush sorted segments, compact in background. Write-optimized; powers Cassandra, RocksDB, ScyllaDB
  • B-trees: in-place updates, balanced tree on disk pages. Read/update-optimized; powers Postgres, MySQL, most OLTP
  • Tradeoff: LSM has write amplification from compaction but high write throughput; B-trees have predictable reads but more write overhead
  • Column stores: store each column contiguously; pair with compression and vectorized execution — the basis of every analytical warehouse
WarehouseLakeLakehouse
StoresStructured, modeledRaw, any formatRaw + table format
SchemaOn writeOn readOn read, enforced via table format
EngineSnowflake, BigQuery, RedshiftS3/GCS + SparkDatabricks, Iceberg + engine
StrengthFast SQL, governanceCheap, flexibleBoth — ACID on cheap storage

Key shift: separation of storage and compute. Data lives once in object storage; multiple elastic engines query it. No more copying data into a proprietary warehouse just to query it.

Iceberg / Delta Lake / Hudi

Key ideas:

  • The problem they solve: a directory of Parquet files has no transactions, no schema evolution, no atomic updates, no consistent reads during writes
  • How: a metadata layer (manifest files, transaction log) over the data files tracks which files make up a table version
  • What you get: ACID transactions, time travel (query a past snapshot), schema and partition evolution, concurrent readers/writers, efficient upserts/deletes (MERGE)
  • Iceberg vs Delta vs Hudi: Iceberg is engine-agnostic and the emerging open standard; Delta is Databricks-native; Hudi specializes in fast upserts and incremental processing

The biggest performance lever

Key ideas:

  • Partitioning: split a table by a column (usually date) so queries scan only relevant partitions — partition pruning. Watch for skew and over-partitioning (too many tiny files)
  • Clustering / sorting: physically order data within partitions on common filter columns so predicate pushdown skips row groups
  • Hidden partitioning (Iceberg): partition transforms decouple the partition scheme from the query, avoiding the classic “forgot the partition filter” full scan
  • File sizing & compaction: many small files kill performance; periodically compact into right-sized files (~100MB-1GB)

Kimball — The Data Warehouse Toolkit

Key ideas:

  • Star schema: a central fact table (measurements — sales, clicks) surrounded by dimension tables (context — customer, product, date)
  • Grain: define the level of detail of a fact row first — one row per order line, per session, etc. Everything else follows
  • Facts: additive (sum across all dimensions), semi-additive (sum across some), non-additive (ratios)
  • Slowly Changing Dimensions (SCD): Type 1 (overwrite), Type 2 (new row + validity dates, preserves history), Type 3 (previous-value column)
  • Snowflake schema: normalized dimensions — saves space, costs joins; usually not worth it in columnar warehouses

Key ideas:

  • Zone maps / min-max stats: per-block metadata lets the engine skip blocks that can’t match a predicate
  • Bloom filters: probabilistic membership test to skip files for point lookups (see Probabilistic Structures)
  • Materialized views: precompute expensive aggregations; trade storage + refresh cost for query speed
  • Caching: result cache and metadata cache in modern warehouses make repeated queries nearly free

Key ideas:

  • Pruning before scanning: partition + cluster so the engine reads less — bytes scanned is the cost unit in BigQuery/Snowflake
  • Avoid SELECT *: columnar means you pay per column read
  • Right-size compute: warehouse size / slot count vs query latency; autosuspend idle compute
  • Storage tiering: hot (SSD) vs cold (object storage / Glacier) by access frequency

Access patternUseWhy
High-volume writes, key lookupsLSM (Cassandra, RocksDB)Write throughput
Transactional reads + updatesB-tree (Postgres, MySQL)In-place updates, indexes
Analytical scans/aggregatesColumnar warehouse / ParquetColumn pruning, compression
Raw + ACID on cheap storageLakehouse (Iceberg/Delta)Transactions on object storage
Local/embedded analyticsDuckDBZero-setup columnar OLAP
ConceptConnected TrackApplication
Storage engines, replication, CAPSystem DesignShared distributed-storage core
Bloom filtersProbabilistic StructuresFile/block skipping
B-trees, sorting, hashingTreesIndex internals
CompressionInformation TheoryColumnar encoding
Object storage as model storeLLM SystemsLoading weights from S3/GCS
CompanyHow This AppearsDifficulty
SnowflakeSeparation of storage/compute, micro-partitionsExpert
DatabricksDelta Lake, lakehouse, IcebergExpert
GoogleBigQuery internals, Dremel, columnarExpert
AmazonRedshift, S3, Iceberg on GlueAdvanced
NetflixIceberg (created here), petabyte tablesExpert