Grain is the answer to: "What does one row represent?"
Examples:
- One row per order
- One row per order line
- One row per customer per day
- One row per page view event
If the grain is unclear, joins and aggregates silently double-count.
fct_orders grain: 1 row per order join to order_items (1 row per line) without care -> revenue duplicated across lines
How to protect grain
- Document it in the model description
- Enforce uniqueness tests on the grain key
- Aggregate to the needed grain before joining facts
Interview tip: Start modeling answers with grain. Interviewers notice that habit.