The classic tradeoff between a flat star and a normalized snowflake, and exactly when each one is the right call.
⏱ 11 min readTopics chapter readerLevel · Dimensional & Warehouse
01 · Overview
Start here
⏱ 5 min · Topic 1 of 9
A fact table holds the numbers of events, such as one row for each order item. A dimension table holds the words that describe them, such as the product name or the country.
A schema is the set of tables in a database and how they link. This chapter compares two shapes for the same shop data: the star and the snowflake.
In a star, the fact table sits in the middle. Flat dimension tables surround it. Flat means that one table holds all the words about one thing.
In a snowflake, the dimensions are split into more tables. This is normalization from the last chapters, applied to the dimensions.
What you will learn
Build the shop as a star.
Split the same dimensions into a snowflake.
Write the same query on both. Count the joins.
Compare the good and bad sides, and know when a snowflake is worth it.
Share one dimension between two fact tables.
02 · Shape 1
The star schema
⏱ 12 min · Topic 2 of 9
Here is the shop as a star. A fact table sits in the middle. We use the shop ids as keys, to keep the tables small.
fact_order_items has one row for each item on an order. It also holds the customer, copied from the order. Now one fact row reaches both dimensions.
fact_order_items (7 rows)
order_id
product_id
customer_id
quantity
101
1
1
2
101
2
1
1
102
3
1
1
103
4
2
1
104
1
3
3
106
5
4
1
106
4
4
1
fact_orders has one row for each order. Its measure, the number you add up, is amount. Order 105 has no amount yet, so it shows NULL, which means no value.
fact_orders (6 rows)
order_id
customer_id
status
amount
101
1
paid
40.00
102
1
paid
25.00
103
2
refunded
60.00
104
3
paid
15.50
105
3
pending
NULL
106
4
paid
80.00
Now the dimensions. In a star they are flat: every word about a product or a customer sits in one row. We add a category for each product, and a country name for each customer.
dim_product (5 rows)
product_id
name
category
1
Pen
Writing
2
Notebook
Writing
3
Bag
Travel
4
Lamp
Home
5
Chair
Home
dim_customer (5 rows)
customer_id
name
country_code
country_name
1
Asha
IN
India
2
Ben
GB
Great Britain
3
Carla
US
United States
4
Dev
NULL
NULL
5
Omar
IN
India
Look at the repeats. The word Writing is stored twice, for Pen and Notebook. The word India is stored twice, for Asha and Omar.
A flat dimension repeats words. That is its cost.
The picture shows the star for fact_order_items. fact_orders works the same way.
PK means primary key: the column that names each row. A foreign key (FK) is a column that holds a key from another table. Each FK here points at one dimension.
The shop as a star
fact_order_items
ColumnTypeKeys
order_idint
product_idintFK
customer_idintFK
quantityint
dim_product
ColumnTypeKeys
product_idintPK
nametext
categorytext
dim_customer
ColumnTypeKeys
customer_idintPK
nametext
country_codetextNULL
country_nametextNULL
One fact table in the middle. Each dimension is one flat table, one join away.
Units for each category
A star answers this question with one join. Join the fact to dim_product, then group by category:
Order 106 is gone. Dev has no country code, so the join finds no match and drops his 80.00.
The total is now 80.50 instead of 160.50. No error appears. In a star this cannot happen here, because the country sits in the same row as the customer.
Watch out
Every extra join is a place to lose rows. Use LEFT JOIN toward a snowflaked table that can be empty. Another fix is to add an “Unknown” row to dim_country and point Dev at it. Then the join always finds a match.
05 · Compare
Star vs snowflake: trade-offs
⏱ 9 min · Topic 5 of 9
Both shapes hold the same data and give the same answers. They differ in two things: the number of joins, and the number of places a word is stored.
BI tools are the tools that draw charts and dashboards. They work best when each dimension is one table.
Star vs snowflake in the shop
Question
Star
Snowflake
Joins for units by category
1
2
Joins for revenue by country
1
2
Tables in the picture
3
5
Places that store the word Writing
2 rows (Pen, Notebook)
1 row in dim_category
Rename a category
Update every product row
Update 1 row
Easy for chart tools (BI)
Yes. One join for each dimension
Harder. Chains of joins
Rename a category
The shop renames Writing to Stationery. In the star, you must change every product row that says Writing:
These are the rows of the flat dim_product. People who write reports see a star. The category name still lives in one place.
The modern default
Many teams build a star. Simplicity wins: fewer joins, fewer mistakes, and an easier model for new teammates.
Interview question: star or snowflake?
A star has one fact table in the middle and flat dimensions, so each dimension is one join away. A snowflake splits those dimensions into more tables, so it repeats less text but needs more joins. I default to a star because it is simpler to query. I snowflake only a large, shared hierarchy that changes.
07 · One more shape
Many facts, one dimension
⏱ 6 min · Topic 7 of 9
The shop has two fact tables: fact_orders and fact_order_items. Both point at dim_customer. The picture shows the two stars sharing one dimension:
Two facts share dim_customer
fact_orders
ColumnTypeKeys
order_idintPK
customer_idintFK
amountnumeric(10,2)NULL
dim_customer
ColumnTypeKeys
customer_idintPK
nametext
country_nametextNULL
fact_order_items
ColumnTypeKeys
order_idint
product_idintFK
customer_idintFK
quantityint
fact_orders and fact_order_items both use the same customer table.
Several stars that share dimensions are called a fact constellation. A shared dimension is a conformed dimension: every fact uses the same keys and the same words.
Because of this, two reports can use the same country labels. Here are units for each country, from fact_order_items: