data-modeling · git:20260829.635d8e8 · 2026-08-29 · sha256 db0f36e998e153b4

data-modeling git:20260829.635d8e8A

Immutable. This exact content is served forever at /api/v1/blob/db0f36e998e153b4.

---
name: data-modeling
description: Designs the warehouse and semantic layer — source-to-mart structure, dimensional modeling, grain, slowly changing dimensions, and the metric layer analytics reads through. Use this to design or restructure a warehouse, model a new source, decide on grain or table structure, build a semantic or metric layer, or diagnose why queries are slow, wrong, or impossible to write.
---

# Data modeling

## Layers, and why the middle one matters

Three layers, each with one job:

1. **Raw** — source data, unmodified, append-only. Never transform on ingest; you cannot recover what
   you discarded, and you will want it.
2. **Staging** — cleaned and conformed: consistent types, standardized names, deduplicated, no
   business logic yet.
3. **Marts** — business-facing models shaped for how questions are asked.

The discipline that pays is keeping business logic out of layers 1 and 2. Logic embedded in ingestion
cannot be changed retroactively, and it will need to change.

## Grain is the decision everything follows from

State the grain of every table in one sentence: *one row per what*. "One row per order line per day"
is a grain. "Order data" is not.

Most modeling errors are grain errors, and they surface as fan-out — a join multiplying rows so every
downstream sum is inflated. If a number is mysteriously too high, check the grain before checking the
logic.

## Dimensional structure

Facts for events and measurements; dimensions for the things being described. Keep facts narrow and
long, dimensions wide and short.

Conform dimensions across facts — one customer dimension, used everywhere. Separate customer tables
per domain is how the same customer gets counted differently in two reports.

**Handle history deliberately.** Overwriting a dimension attribute rewrites the past: last year's
revenue silently re-attributes to this year's segment. Decide per attribute whether history matters,
and where it does, keep versions with valid-from and valid-to.

## The semantic layer

Define metrics once, above the marts, and have every consumer read through it. Without it, the same
metric is reimplemented in each dashboard and they drift — not because anyone is careless, but
because a filter differs.

The semantic layer is where the metric dictionary becomes executable rather than documentary.

## Performance

Model for the query pattern you actually have. Pre-aggregate what is queried constantly; leave the
long tail to compute on demand.

Partition and cluster on what people filter by — usually time, then a tenant or entity key. Most slow
warehouse queries are full scans of a table that could have been partitioned by date.

Denormalize deliberately, and write down why. Undocumented denormalization is indistinguishable from
a modeling error six months later.

## Never

- Build a mart directly on raw. The coupling means every source change breaks the business layer.
- Mix grains in one table.
- Let a dashboard contain business logic the warehouse does not. That logic is invisible and
  unversioned.