DATA ARCHITECTURESchema Design

Star vs Snowflake Schemas

How data engineers design data that lasts — pick a topic on the left and its full breakdown loads here: the mental model, ERDs and worked schemas, trade-offs, edge cases, and the decisions that separate a durable model from a fragile one.

18 min readTopics chapter readerLevel · Dimensional & Warehouse
01 · Orientation

What You'll Master Here

Star = flat dimensions, fewer joins, cheap redundancy. Snowflake = normalized dimensions, more joins, less redundancy. Same information either way.

4 min · Topic 1 of 7

Chapter 8 built a star with deliberately flat dimensions. A snowflake is the same data with those dimensions normalized. Turn the dial below and watch what normalizing actually costs — and what it never changes.

The chapter runs on one warehouse throughout: Lumen Cinemas, 62 sites, one row per ticket sold — 144 M fact rows over eight years, 4.6 M of them in the last quarter, against a 41,000-row dim_film. By the end you should be able to look at a dimension attribute and say, with evidence, whether it stays flat or earns its own table.

Core mental model

Star = flat dimensions, fewer joins, cheap redundancy. Snowflake = normalized dimensions, more joins, less redundancy. Same information either way.

Why it matters

Star vs snowflake is decided by reflex more often than by argument, and the reflex is usually "normalization is correct" — an instinct borrowed from OLTP that quietly taxes every analytical query.

star schema
Fact surrounded by flat, denormalized dimensions; one join per dimension.
snowflake schema
A star whose dimensions are normalized into linked sub-tables; multiple join hops.
outrigger
A single normalized sub-table hung off one dimension, rather than snowflaking the whole model.
fact constellation
Several fact tables sharing conformed dimensions (a "galaxy" of stars).
One dimension, four normalisation levelsLumen Cinemas asks: admissions by studio group, last quarter. Turn the dial and watch what changes.
One flat dimension
  • dim_film41,000 rows · film_title, genre, certificate, distributor_name, studio_group
select f.studio_group, count(*) as admissions
from fact_ticket_sale t
join dim_film f on f.film_key = t.film_key
group by f.studio_group;
What the dial moved
  • Joins to reach studio_group: 1
  • Joins to reach genre: 1
  • Tables in this dimension: 1
  • 18,400 film rows carry the text "Meridian Group"
What the dial never moved
studio_groupadmissions
Meridian Group2,411,400
Northgate1,588,200
Kestrel600,400
Identical at all four levels. Star and snowflake hold the same information; only the cost of getting it out changes.
Level 0One flat dimensionEvery attribute of a film is one join from the fact. The studio name is stored 18,400 times — as 18,400 references to one dictionary entry, which is why it costs almost nothing.
Common mistake

Snowflaking every dimension because normalization "feels correct". You add joins and complexity to every query for storage savings that compression already delivered.

Better habit

Default to a star; snowflake only with a written reason.

Judge the choice by query cost and ownership, not tidiness.

Normalize the specific attribute, not the whole model.

The big idea

In analytics, redundancy inside a dimension is cheap and joins are expensive — the opposite of the OLTP instinct. Chapter 5 taught you to remove redundancy; this chapter is where you learn when not to.

Chapter 5: normalization & denormalization
Remember this

Star and snowflake are the same information at different normalization levels; the dial moves join count and storage, never the answer.