skip to content

When is snowflaking a dimension into normalized sub-tables actually the right call?

level: middleimportance: should knowfreq 50%

answer

  1. is the benefit storage or ownership?
  2. how big is the dimension, really?
  3. who masters that hierarchy level?
  4. does the level change on its own schedule?
  5. normalize where you load, flatten where you query

basics

~20 s

Snowflake when a hierarchy level is huge and repeated, is mastered and governed upstream as its own reference entity, or changes on a different cadence than the dimension. Even then, most teams normalize the load layer and publish a flattened dimension.

solid answer

~50 s

Three conditions genuinely justify it. First, **scale with repetition**: a dimension of hundreds of millions of rows carrying a wide block of attributes that take only a few thousand distinct combinations — splitting that block out is a real saving, not a rounding error. Second, **ownership**: a hierarchy that an upstream master-data system governs as its own entity, where every mart must agree on it and a single reference table is the control. Third, **cadence and history**: a level that changes on its own schedule or needs its own versioning, which is far cleaner as a separate table than as columns in a dimension you rewrite for unrelated reasons. Note what is *not* on the list: aesthetic normalization, or storage savings on an ordinary dimension. And the usual resolution is a hybrid — normalized reference tables where the data is loaded and governed, flattened star tables where analysts query.

go deeper

for a junior

Know that snowflaking is the exception, and be able to name one honest reason for it, such as a hierarchy level that another system owns and every mart must share.

for a middle

Be ready to state the conditions quantitatively — dimension size, distinct combinations of the repeated block, change cadence — and to describe the normalize-then-flatten hybrid.

for a senior

Show you would measure before splitting, and that you know flattening is only safe when every sub-table contributes at most one row per parent.

for a principal

Frame it as where governance sits: which layer owns a hierarchy, who is accountable for it, and what consumers should be shielded from entirely.

## Start from what the snowflake actually buys A normalized dimension buys exactly two things: each label is stored once, and each hierarchy level exists as an addressable entity in its own right. Everything else — joins, comprehension, load ordering — it costs. So the question is only ever: is one of those two benefits load-bearing for *this* dimension? ## Condition 1 — a very large dimension with a wide, highly repeated block The storage argument fails on ordinary dimensions because they are small. It does not fail on all of them. Consider a customer dimension of 300 million rows carrying a 40-column demographic and geographic block whose values take only a few thousand distinct combinations. Splitting that block into its own table and leaving a key behind removes a genuinely large amount of duplicated data, and it also decouples updates to the block from updates to the customer row. This is a scale threshold, not a principle: run the numbers before you invoke it. (The related pattern of a separately-keyed attribute cluster is a dimension-design pattern in its own right and is covered under degenerate, junk and mini-dimension patterns; here the point is simply that size can flip the trade-off.) ## Condition 2 — the level is a governed entity someone else masters Some hierarchy levels are not really attributes of the dimension; they are entities the enterprise manages separately. A chart of accounts, a regulatory product classification, an organizational unit tree published by HR. When an upstream master-data system owns that list, keeping it as one reference table gives you a single place to load it, test it and prove that every mart uses the same version of it. Flattening it into six different dimensions makes divergence possible and hard to detect. Note the boundary: making sure two marts *mean the same thing* by a shared dimension is conformance, a separate subject. Here the argument is narrower — a governed level is easier to maintain as one table. ## Condition 3 — different change cadence or its own history If a product's description changes weekly but its department assignment changes twice a decade, versioning them together means rewriting department history for description edits. Keeping the slow, governed level in its own table with its own effective dating is often simpler and produces much less history churn. The mechanics of that versioning belong to slowly-changing-dimension design; the shape decision belongs here. ```sql -- normalized reference level, loaded and versioned on its own cadence CREATE TABLE dim_department ( department_key BIGINT PRIMARY KEY, department_code VARCHAR(20), department_name VARCHAR(100) ); ``` ## Weak reasons candidates offer - *"It is more normalized, so it is better design."* Normalization protects write integrity under concurrent updates. A mart has one writer and read-only consumers; the goal is read clarity. - *"It saves storage."* True in the trivial sense and immaterial on any normal dimension. Compute the number before you claim it. - *"The hierarchy is deep."* Depth is a reason to model the hierarchy carefully, not automatically a reason to split it into tables. A ten-level fixed hierarchy is still fine as ten columns. - *"Our tool prefers it."* Some presentation tools do model levels explicitly, and that is a legitimate constraint to respect — but let the tool's requirement be the stated reason, not a claim about modelling purity. ## The hybrid that usually wins In practice you rarely have to choose globally. Keep the normalized reference tables in the layer where data is integrated and governed — that is where the maintenance and ownership benefits live — and publish a flattened, wide dimension to the consumption layer, materialized or as a view: ```sql CREATE VIEW dim_product_flat AS SELECT p.product_key, p.sku, p.product_name, b.brand_name, c.category_name, d.department_name FROM dim_product p JOIN dim_brand b ON b.brand_key = p.brand_key JOIN dim_category c ON c.category_key = b.category_key JOIN dim_department d ON d.department_key = c.department_key; ``` Analysts see one table; the loader keeps one authoritative copy of each label. The one caution: flattening only works if each sub-table contributes at most one row per parent. If a product can belong to several categories, the join multiplies rows and inflates any measure joined through it — that case is a multi-valued relationship needing a different construct, not a flattening. ## How to answer Name the conditions, state that they are quantitative rather than aesthetic, and finish with the hybrid. An answer that says "never snowflake" is as unconvincing as one that snowflakes by reflex.

  • Your dimension has one hierarchy level mastered upstream. Must analysts see it as a separate table?
    No, and usually they should not. Keep the governed reference table in the integration layer as the single place it is loaded and tested, then publish a flattened dimension that joins it in. Consumers get one join path while you keep one authoritative copy of the labels.
  • What breaks if you flatten a snowflaked dimension whose sub-table has several rows per parent?
    The join multiplies dimension rows, and any fact measure aggregated through it is counted once per matching sub-row, so totals inflate. That relationship is multi-valued rather than hierarchical, and flattening is the wrong tool for it — the shape needs a different construct entirely.
  • How would you test the claim that snowflaking a specific dimension saves worthwhile storage?
    Measure it. Take the dimension's row count times the width of the candidate attribute block, compare it with the total footprint of the marts it serves, and check how many distinct combinations the block actually has. If the answer is a fraction of a percent, the argument is decided.

saying these in an interview costs you the question

  • Snowflakes by default because normalization is better design
  • Cites storage savings without ever computing them
  • Ignores that flattening breaks when a sub-table has multiple rows per parent
  • Thinks deep hierarchies must always become separate tables
  • Cannot name a hybrid that normalizes loading and flattens consumption

context