In a one-big-table mart, what does copying every dimension attribute onto each fact row cost you?
answer
- a copy, not a pointer
- storage is not the real cost
- how much does one correction rewrite?
- who owns the definition now?
- cost scales with history, not with the change
basics
~20 sDuplicated attributes make every correction a rewrite of history instead of a one-row dimension update, spread the same business definition across marts where copies drift, and make rebuild cost scale with history rather than with the size of the change.
solid answer
~50 sStorage is the least of it — a repeated low-cardinality attribute compresses well on a columnar engine. The real costs are logical. First, **restatement**: fixing a mis-classified customer segment means rewriting every order row that carries the copy, so the cost of a one-value correction scales with years of history rather than with the change. Second, **no single owner**: the definition of that attribute now lives inside each wide mart that copied it, and two marts built at different times, or by different teams, disagree with nothing to reconcile them against. Third, **rebuild economics**: adding or reclassifying an attribute means a backfill of a huge table, not an update to a small dimension every fact already points at. The mitigations are to keep the durable business key on every row, derive all wide marts from one upstream definition, and rebuild incrementally by event-date partition.
code
sql · 9 lines-- star: one row, independent of history size
UPDATE dim_customer
SET customer_segment = 'ENTERPRISE'
WHERE customer_id = 8814;
-- wide mart: every order that customer ever placed
UPDATE orders_wide
SET customer_segment = 'ENTERPRISE'
WHERE customer_id = 8814;go deeper
Know that a wide mart stores the attribute value itself on every row rather than a key pointing at one dimension row, so the same value exists many times over.
Explain the mechanics of a correction in both shapes — one dimension row versus every affected fact row — and why the cost scales with history rather than with the size of the change.
Demonstrate the operational fix: partitioned deterministic rebuilds, durable keys kept on the row, and a per-attribute decision about which copies are frozen and which are refreshed.
Own the governance angle: duplicated values are acceptable, duplicated definitions are not. Set the rule that every wide mart selects a definition owned upstream rather than restating it.
## The trade you actually made When you flatten `dim_customer` into `orders_wide`, you replaced a **pointer** with a **copy**. In the star, four billion order rows carried a customer key and the attribute existed once. In the wide mart, the attribute value itself exists four billion times. Everything that follows is a consequence of copies not having a single owner. ## Storage duplication is the weakest objection Candidates reach for storage first, and interviewers usually push back. `customer_segment` has maybe six distinct values; a columnar engine stores it as a small dictionary plus compact codes, so four billion repeats is not four billion strings. The byte cost of a wide mart is real but rarely decisive. Say this out loud — it shows you know where the cost actually is. ## Restatement: the correction problem In a star, correcting a mis-classified customer is one statement against one small table: ```sql UPDATE dim_customer SET customer_segment = 'ENTERPRISE' WHERE customer_id = 8814; ``` Every report that joins through the dimension picks the correction up on its next run. In the wide mart the same correction is: ```sql UPDATE orders_wide SET customer_segment = 'ENTERPRISE' WHERE customer_id = 8814; ``` which touches every order that customer has ever placed. One customer is survivable; a source system reclassifying a whole taxonomy is a full-table rewrite. The cost of a correction has stopped scaling with the **size of the change** and started scaling with the **size of history**. On engines whose files are effectively immutable, that rewrite is also not a cheap in-place edit — it rewrites data, which is a batch-window and cost question, not a one-line fix. This has a second-order effect worth naming: because restatement is expensive, teams postpone it, and the mart quietly carries values everyone knows are wrong. ## Loss of a single place for the logic The deeper cost is organisational. `customer_segment` is not raw data; it is a definition — probably a CASE expression over revenue bands, contract type and account age. In a star that expression lives once, in the transform that builds the dimension, and every fact that joins to it inherits the same answer. Copy it into three wide marts and you have three implementations. They start identical and drift: someone adds a band in the orders mart in March, nobody touches the subscriptions mart, and by June the two dashboards disagree by a few percent with no shared object to reconcile them against. Finding the drift means diffing SQL across marts rather than reading one dimension's definition. This is why a wide mart is much safer as a **generated** artifact: the definition stays upstream in the modelled core, and every OBT selects it rather than restating it. ## Rebuild and evolution cost Adding an attribute in a star is `ALTER TABLE dim_customer ADD COLUMN …` plus a small backfill; every existing fact row already points at the dimension and gains the attribute for free. Adding it to a wide mart means adding the column and backfilling it across all history, because the fact rows carry copies, not pointers. Wide marts therefore evolve in expensive lurches, and the standing answer is to make them cheap to regenerate — deterministic, partitioned by event date, rebuilt for the affected partitions only — so that a change is a re-run of a bounded slice rather than a bespoke migration. ## What good practice looks like - **Keep the durable business key on every wide row** (`customer_id`, not just the flattened attributes). It is the escape hatch: consumers can join to a small current-attribute table when they need a value the mart froze, and rebuilds can locate affected rows. - **Partition the wide mart by event date** and rebuild by partition, so a correction that only affects last month is a last-month job. - **Define each derived attribute once, upstream**, and have every OBT select it. Duplicated *values* are tolerable; duplicated *definitions* are the defect. - **Copy deliberately, not exhaustively.** Flatten the attributes consumers actually filter and group by. A wide mart that copies every column of every dimension maximises the restatement surface for attributes nobody queries. - **Decide per attribute whether the copy is frozen or refreshed.** A price paid at order time is meant to be frozen forever; a customer's current country is not. Treating both the same is how a mart ends up neither correct as-of nor correct today. ## The one-line answer Duplication is cheap in bytes and expensive in change. You bought join-free reads by paying every future correction in proportion to your history, and by giving up the single place where an attribute's definition lived.
- How do you make corrections to a wide mart affordable rather than avoiding them?Make the mart deterministic and rebuildable by slice: partition it by event date, keep the transform a pure function of the modelled core, and re-run only affected partitions. Keep the durable business key on every row so you can locate the rows a correction touches. The goal is that a fix is a bounded re-run, never a bespoke migration.
- Which attributes should you deliberately never refresh in a wide mart?Anything whose business meaning is "as it was at the time": the price paid, the discount applied, the plan the customer was on when the event happened. Those are facts about the event, not descriptions of the entity today, and refreshing them silently rewrites reported history. Attributes describing the entity's current state are the ones that may legitimately be refreshed.
- If duplication is mostly a change-cost problem, when is it actually cheap?When the copied attributes are effectively immutable — a product's category at launch, a store's opening region, a date's fiscal period — and when the mart is small enough or partitioned finely enough that a rebuild is routine. Slow-changing, rarely corrected attributes on a rebuildable table are close to free; volatile, frequently restated ones are where the bill lands.
saying these in an interview costs you the question
- Names storage bloat as the main cost of duplication
- Thinks a corrected attribute propagates automatically to a wide mart
- Refreshes every copied attribute, silently rewriting reported history
- Copies the same derived definition into several marts
- Assumes a full-history rebuild is always available in the batch window