Section C · Trade-offs

The Big Trade-offs

Six forks that appear in every ML data design conversation. Each as a decision matrix with the condition that flips it — and the one-line answer that defends the fork instead of saying "it depends".

How to use a matrix in the room

A trade-off matrix is not something you recite; it's the shape of your reasoning when the interviewer says "why not the other one?" The pattern that works: name the requirement that dominates, pick, state the cost honestly, and name the flip condition. The rows below are the dimensions interviewers actually pull on. Learn the flip conditions cold — they are the difference between a defended decision and a preference.

Where the depth lives

Each fork points to the deep-dive chapter that carries the full argument. In the interview you need the matrix and the sentence; the chapter is for the follow-up where they want you to go three levels down.

Batch vs streaming features

The most common fork, and the one where candidates over-reach. The default is batch; streaming earns its place when a specific feature's value decays in minutes. Deep dive: 06 · Streaming Features.

DimensionBatch (hourly/daily materialisation)Streaming (event-time aggregation)
FreshnessMinutes to a daySub-second to seconds
Correctness modelReproducible from tables; point-in-time joins are easyWatermarks, late events, exactly-once are yours to get right
Training/serving paritySame SQL offline and online (materialised)Needs a stream-batch unified definition or you will skew
Cost profileCheap compute, storage-heavyAlways-on cluster, ops-heavy
Failure modeStale featuresWrong features (silently)
Typical useAggregates over days/weeks, profile features, embeddingsVelocity counts ("txns in last 5 min"), session state, real-time context
Defend the fork

"I'd keep 90% of features batch because they aggregate over days and batch gives me reproducibility for free; I'd stream only the handful whose value decays in minutes — the 5-minute velocity counts for fraud — and I'd flip more features to streaming only when a measured lift from freshness justifies the operational cost."

Warehouse vs lakehouse for ML

A warehouse is a superb place to compute tabular features; it is a poor place to store images, tensors, or ten thousand versioned training sets. The fork is really "where does the ML data live", not "do we keep Snowflake". Deep dive: 05 · Storage, Formats & Versioning and 13 · Reference Architectures.

DimensionWarehouse-centric (Snowflake / BigQuery)Lakehouse-centric (Iceberg / Delta on object storage)
Tabular featuresExcellent — SQL, governance, semantic layerGood — Spark/Trino/DuckDB; more assembly
Unstructured dataAwkward; external stages at bestNative — files, Lance/Parquet, tensors alongside tables
Training-data accessExport to files; egress and copiesDirect reads from training jobs; no export step
Versioning / time travelTime travel with retention limits; cloningSnapshots as first-class; branch/tag semantics
Cost at scaleCompute credits climb with feature backfillsObject storage cheap; compute you run yourself
Team fitAnalytics-heavy org, small ML teamML-heavy org, platform team exists
Defend the fork

"Compute tabular features where the governed data already is — the warehouse — and land training sets and unstructured data in the lakehouse where training jobs read them directly. I'd flip to lakehouse-only when backfill credits or export volume start to dominate the bill, and to warehouse-only if the ML footprint stays small and tabular."

Build vs buy a feature store

The honest starting point: most teams need the discipline of a feature store (registry, point-in-time correctness, one definition offline and online) before they need the product. Deep dive: 04 · The Feature Store.

DimensionBuild (tables + conventions + a thin online cache)Open source (Feast, Hopsworks)Managed (Tecton, Databricks, SageMaker, Vertex)
Time to first modelFast for one teamMedium — you operate itFast — but onboarding and lock-in
Point-in-time joinsHand-written; easy to get wrongBuilt inBuilt in, with materialisation managed
Streaming featuresSeparate buildPartial; you wire the stream jobFirst-class in some (Tecton)
Online servingYou own the cache and its SLOsPluggable store; you run itIncluded, with SLOs
CostEngineer timeEngineer time + infraLicence + infra; predictable
Right when< ~5 models, one team, batch-heavyPlatform team exists, wants control, avoids lock-inMany teams, real-time needs, small platform team
Defend the fork

"Below five models I'd build: versioned feature tables, a registry in code, and a Redis cache — and be strict about point-in-time joins. I'd buy the moment a second team needs the same features online, or a real-time feature's freshness SLO becomes a contract, because that's when the operational surface stops being a side project."

Online store choices

The online store serves a feature vector for one entity in single-digit milliseconds. The choice is dominated by access pattern (point reads by key), write pattern (batch materialisation vs streaming updates), and how much operational burden you can carry. Deep dive: 08 · Serving Architectures.

DimensionRedis / ValkeyDynamoDBCassandra / ScyllaDBBigtable
p99 read latency< 1 ms (in-memory)~5–10 ms~2–10 ms~5–10 ms
Dataset size fitMemory-bound — tens of GB per nodeUnbounded, pay per requestMulti-TB, disk-backedMulti-TB to PB
Bulk load from batchFast; pipeline itThrottled by write capacity; costly at scaleGood with SSTable loadingExcellent with Dataflow/bulk import
Streaming updatesTrivialGoodGoodGood
TTL / expiryNativeNativeNativePer column family (GC rules)
Ops burdenLow managed / medium self-run; memory planningNone (AWS)High self-run; medium managedLow (GCP), Google-only
Cost driverMemoryRequest units, write-heavy backfillsNodesNodes + storage
Defend the fork

"Redis for a feature set that fits in memory with a sub-millisecond budget; DynamoDB or Bigtable when the entity space is hundreds of millions and I want zero ops; Cassandra only if I already run it. The flip is size × write pattern — the day a nightly backfill of 200M rows makes DynamoDB's write bill the biggest line, I move to a bulk-load-friendly store."

Dataset versioning approaches

"Which data trained model v14?" must be answerable in one query, for reproducibility, audit and debugging. The mechanisms differ in granularity and in what they version — table snapshots, files, or a whole repository of data. Deep dive: 09 · Lineage & Reproducibility.

DimensionIceberg snapshots / tagsDelta time travelLakeFS (git for object storage)DVC (git-linked file versioning)
Unit versionedA tableA tableA whole bucket/repo of tables and filesFiles/directories tracked from a git repo
BranchingTags; branches (newer specs)No branches; clonesFull branch/merge semanticsVia git branches
Cross-table consistencyPer table; coordinate manuallyPer tableAtomic commit across many tablesPer repo snapshot
RetentionSnapshot expiry you controlRetention window (default days)Until you delete the branchUntil you prune
Unstructured dataNot the pointNot the pointYes — files are first-classYes — its original purpose
Best fitTabular training sets in a lakehouseDatabricks shopsMulti-table datasets, images + tables, experiments on branchesSmall teams, research, files alongside code
Defend the fork

"For tabular training data I'd tag the Iceberg snapshot and record the tag in the model registry — zero extra infrastructure. I'd add LakeFS when a training set spans several tables and files that must be consistent as a unit, or when teams need branches to experiment without copying data."

Vector store choices

Size the problem before naming a product: vectors × dimensions × bytes. Under a few million vectors an extension in the database you already run is usually right. Deep dive: 07 · Embeddings & Vector Data.

Dimensionpgvector (Postgres)Dedicated engine (Qdrant, Weaviate, Milvus)Managed service (Pinecone, cloud-native)Lakehouse-native (Lance / LanceDB)
Scale sweet spot≤ ~5M vectors10M–1BAny, priced per unitBatch/offline first; growing online story
Filtered searchSQL WHERE + index; can degradeFilter during traversal; strongMetadata filters; strongScalar indexes + prefilter
OpsNone new — it's PostgresA new cluster to runNone; lock-in and egressFiles on object storage; minimal
Multi-tenancyRow-level; partition tablesCollections/partitions; goodNamespaces; goodPer-dataset
CostExisting DB capacityNodes (memory for HNSW)Highest per vector at scaleStorage-priced
Best fitSmall corpora, transactional joins matterLarge corpora, high QPS, filtersSmall team, fast start, no opsTraining/eval data, offline retrieval, ML-native workflows
Defend the fork

"Six million vectors with tenant filtering at 200 QPS — pgvector would strain on filtered recall, so I'd run a dedicated engine with filtered HNSW; below a couple of million I'd have stayed in Postgres. I'd move to managed if the team can't carry another cluster, and I'd keep the chunk table in the lakehouse regardless so the index is always rebuildable."

The decision sentence

Every matrix above collapses to one sentence in the room. Practise it until it's reflex:

Pattern

"Given [the requirement that dominates], I'd choose [option] over [alternative] because [how it meets the requirement]. The cost is [honest downside], acceptable because [context] — and I'd revisit if [flip condition]."

The flip condition is the senior tell. It shows you know the boundary of the decision, not just the decision — and it hands the interviewer a natural follow-up you're already prepared for.

Now put the matrices under pressure: 09 · Practice Questions, Graded.

✓ Check yourself

Answer from memory before opening each one.

  1. A product manager wants a 28-day spend feature "real-time". How do you decide, and what does the answer say about batch versus streaming failure modes?

    Show answer

    Default to batch. A 28-day aggregate barely moves in minutes, so streaming costs an always-on cluster for no lift, and you stream only when measured lift from freshness pays for the operations. Batch fails by going stale, which is visible. Streaming fails by being quietly wrong, because watermarks, late events and exactly-once are yours to get right. See batch versus streaming.

  2. Warehouse backfill credits dominate the bill, training jobs need exports, and the corpus now includes 30 TB of images. Where does each kind of data live?

    Show answer

    Compute tabular features where the governed data already is, and land training sets and unstructured data in the lakehouse where training jobs read directly. If backfill credits or export volume keep dominating, move to lakehouse-only. See warehouse versus lakehouse.

  3. Three models, one team, nightly batch. A vendor offers a managed feature store. What do you do, and what event changes your answer?

    Show answer

    Build the discipline, not the product: versioned feature tables, a registry in code, a Redis cache if anything is online, and strict point-in-time joins. Buy when a second team needs the same features online, or when a real-time feature's freshness SLO becomes a contract. See build versus buy.

  4. The entity space is 300M, a nightly backfill rewrites 200M rows, and p99 reads must be under 10 ms. What does each online store cost you, and what decides it?

    Show answer

    Redis is memory-bound at tens of GB per node, so a hot set that large gets expensive. DynamoDB handles the size but its write bill for a 200M-row backfill can become the largest line. Bigtable or Cassandra with bulk loading suit that write pattern. The decision is size times write pattern. See online store choices.

  5. A training set spans three tables and a folder of images and must be reproducible as one unit. Why is an Iceberg snapshot tag not enough?

    Show answer

    Iceberg versions one table at a time, with no atomic commit across several tables and loose files. LakeFS gives an atomic commit and branches across a whole repository, so the tables and images are consistent as a unit. See dataset versioning approaches.

  6. You have 2M vectors, already run Postgres, need joins to orders, and expect about 20 QPS. Which store, and what would make you move?

    Show answer

    pgvector, because at that size an extension in the database you already run is usually right and joins are easy. Move to a dedicated engine if vectors grow past a few million or filtered search at higher QPS starts to hurt recall. Size the problem before naming a product. See vector store choices.

Takeaway

  • Default features to batch. Stream only those whose value decays in minutes, and only when measured lift justifies the operating cost.
  • Batch fails stale and streaming fails silently wrong, and that difference sets how you monitor each.
  • Compute tabular features where governed data already lives, and put training sets and unstructured data in the lakehouse.
  • Below about five models, build the feature-store discipline. Buy when a second team needs the features online or freshness becomes a contract.
  • An online store is chosen by entity count times write pattern: Redis in memory, DynamoDB or Bigtable at very large size, and bulk-load cost flips the choice.
  • Tag an Iceberg snapshot for single tables, and add LakeFS for multi-table or file-backed datasets or for branches. Size vectors before you name a vector store.
  • Every fork is a decision sentence with a cost and a flip condition.

Next, put those matrices under pressure with questions graded from L1 to L4. → Practice Questions, Graded

Further reading

  • Feast documentation — Feast. The open-source feature store whose registry and stores anchor the build-versus-buy row.
  • Tecton documentation — Tecton. The managed side of the same fork, with streaming features and online serving included.
  • Branching and Tagging — Apache Iceberg documentation. Tags and branches on table snapshots for dataset versioning.
  • Table batch reads and writes — Delta Lake documentation. Includes time travel and its retention behaviour.
  • lakeFS documentation — lakeFS. Git-style branches and atomic commits across object-storage data.
  • DVC documentation — Data Version Control. Versioning files and directories alongside code in git.
  • pgvector — pgvector project README. Vector similarity search inside Postgres, for the small-corpus end of the vector fork.