Skip to content
Back to Resources
Guide

Data Warehouse Modeling: Star Schemas, Kimball, and Grain

Skopx Team
July 31, 2026
16 min read

A finance lead asks something that sounds trivial: what was revenue by sales region last March, using the region assignments that were in place last March. The CRM reassigned territories in January. The reporting table stores one row per opportunity with the current region stamped on it. Every number you hand back is quietly wrong, and it stays wrong until someone notices in October. That failure is the whole reason data warehouse modeling exists. It is not schema aesthetics. It is the discipline of deciding, in advance, what one row means and how the past gets preserved when the present changes.

Most writing on this subject either reprints a star schema diagram with no explanation of why it looks like that, or drowns the reader in Data Vault satellites before they have declared a single grain. This guide does neither. It walks the actual sequence a modeler follows, explains the two or three decisions that determine whether the model survives contact with real questions, and then makes the case that a large share of companies reading it should not build one at all.

What data warehouse modeling actually solves

Transactional databases are normalized because normalization prevents update anomalies. If a customer's billing address lives in exactly one place, you can change it in exactly one place. That is correct behavior for an application and destructive behavior for analysis, because the old address is gone.

A dimensional data warehouse inverts the priorities. It accepts redundancy, sometimes a lot of it, in exchange for three properties an analyst needs:

Queries that a non-specialist can write. A fully normalized order model might require eight joins to answer "revenue by product category by month." A star schema requires two. That difference is not about milliseconds, it is about whether the analyst gets the join conditions right at 6pm before a board meeting.

Stable meaning over time. Dimensional models carry explicit history. When a product moves categories, a well-modeled warehouse can still report last year's numbers under last year's categories, because the old attribute values are still sitting in rows that old facts point to.

Conformance across business processes. Once you have a single customer dimension used by orders, support tickets, and invoices, you can compare those processes side by side. Without it, every team maintains a private definition of "customer" and the numbers never reconcile. That problem is close cousin to the one covered in Master Data Management: MDM Without a Six-Figure Program, and the two disciplines solve it from opposite ends: MDM standardizes the record at the source, dimensional modeling standardizes it at the point of analysis.

Ralph Kimball and Margy Ross formalized this in The Data Warehouse Toolkit, still the canonical reference after three editions. The Kimball data warehouse toolkit's central contribution was not the star diagram, it was the four-step design process: pick the business process, declare the grain, identify the dimensions, identify the facts. Teams that skip step two produce models that fail within a quarter.

Declare the grain before anything else

Grain is the answer to the question "what does one row in this fact table represent?" The answer must be a single sentence with no conjunctions in it.

Good grain declarations:

  • One row per order line item
  • One row per shipment
  • One row per customer per day, capturing the state of their subscription at midnight UTC
  • One row per support ticket status change

Bad grain declarations, all of which look reasonable in a meeting:

  • One row per order, except subscription orders which get one row per billing period
  • One row per customer, with monthly and quarterly totals in separate columns
  • One row per marketing touch, or per conversion, depending on the source

The moment a grain contains "except" or "or," the fact table has two grains, and every aggregate built on it will double count something. Analysts will find the double counting eventually. They will find it in a number that has already been sent to an investor.

Declare grain at the lowest atomic level the source system records. Not the level someone currently asks for. Summarized grain feels efficient and is a trap: the first question that needs a breakdown you did not anticipate forces a rebuild, and there is always such a question. Storage is cheap on every modern platform, and the cost profile of columnar storage is covered in more depth in Amazon Redshift Data Warehouse: Architecture and Costs. Compute against a well-clustered atomic table is rarely the bottleneck people fear.

Facts and dimensions: what goes where

Once grain is fixed, the split is mechanical. Facts are the numbers you sum. Dimensions are the words you group by. If you find yourself wanting to average an attribute, it is probably a fact. If you find yourself wanting to filter on a number, it may still belong in a dimension as a banded attribute.

Three fact table types cover almost everything:

Transaction facts record an event: an order line, a payment, a click. They are the most common and the easiest to model. Measures are typically fully additive, meaning you can sum them across every dimension.

Periodic snapshot facts record state at regular intervals: account balance at month end, inventory on hand each night, active seats per day. Measures here are semi-additive, meaning they sum across products and customers but not across time. Summing a daily balance over thirty days produces a meaningless number. This is one of the most common modeling errors in practice, and BI tools will happily compute it for you.

Accumulating snapshot facts record a pipeline with known milestones: a single row per order that gets updated as it is placed, picked, packed, shipped, and delivered, with a date column for each milestone and lag columns between them. These are the right structure for anything you would describe as a funnel with a fixed set of stages.

There is also the factless fact table, which sounds like a joke and is genuinely useful: a table of events with no measures, used to record attendance, eligibility, or coverage. "Which promotions were a product eligible for, including ones nobody redeemed" is not answerable from a sales fact, because the non-events left no trace.

On the dimension side, a handful of techniques handle nearly every awkward case:

TechniqueUse it whenExample
Degenerate dimensionAn identifier belongs at fact grain with no attributes of its ownOrder number stored on the fact row, no order dimension table
Role-playing dimensionOne dimension is used in several rolesA single date dimension viewed as order date, ship date, due date
Junk dimensionMany low-cardinality flags would otherwise clutter the factA single row combining payment type, channel, and gift flag
Mini-dimensionAttributes change too fast for full history rowsCustomer credit band and age band split from the customer dimension
Bridge tableA genuine many-to-many between fact and dimensionMultiple sales reps credited on one deal
OutriggerA dimension needs a shared sub-dimensionA date attribute referenced from inside the customer dimension

Build a real date dimension, always. Not a date function, a physical table with one row per calendar day and columns for fiscal period, week number, holiday flags, and day-of-week names. Every fiscal calendar question, every "compare to same week last year," and every holiday exclusion becomes a filter instead of a nested expression.

Slowly changing dimensions, and the one type that matters

Slowly changing dimension handling is where the opening scenario is won or lost. The Kimball taxonomy runs from Type 0 to Type 7. In practice you will use two of them.

TypeBehaviorWhat you can answer afterward
Type 0Attribute never changes after loadOriginal values only, correct for things like signup date
Type 1Overwrite the old valueCurrent state only, history is destroyed
Type 2Insert a new row with valid_from, valid_to, is_currentBoth current and point in time, at the cost of more rows
Type 3Add a "previous value" columnExactly one prior state, useful for a single reorganization
Type 4Split volatile attributes into a mini-dimensionFast-changing attributes without exploding the main dimension
Type 6Hybrid of 1, 2 and 3 in one tableReport by current assignment or historical assignment from the same rows

Type 1 is the right default for correcting genuine errors, a misspelled company name, a bad country code. Type 2 is the right default for anything a report might be grouped by that can legitimately change: territory, segment, plan tier, account owner, product category.

Type 2 is also the reason surrogate keys exist. If a customer has three historical rows, the natural key is no longer unique, so the dimension needs its own meaningless integer or hash key, and facts point at the surrogate that was current when the fact occurred. Skip surrogate keys and Type 2 becomes impossible to implement correctly. Add a special row with a reserved key for "unknown" and another for "not applicable" while you are at it, so late arriving facts have somewhere to point instead of being dropped by an inner join.

The practical shortcut worth knowing: dbt snapshots implement Type 2 in roughly ten lines of YAML against any source table, using either a timestamp column or a column set to detect change. A team with no warehouse modeling experience can start capturing history on their five most important tables in an afternoon. Doing that early is far more valuable than getting the full model right later, because history you did not capture is not recoverable at any price.

Star schema vs snowflake schema, and the modern alternatives

The star schema vs snowflake schema debate is older than most people working on it and has a duller answer than the argument suggests. A star schema keeps each dimension in one flat, denormalized table. A snowflake normalizes dimension hierarchies into sub-tables, so product joins to category joins to department.

ConsiderationStar schemaSnowflake schema
Query complexityOne join per dimensionMultiple joins per hierarchy
StorageRedundant, but columnar compression makes it near-freeMarginally smaller
BI tool supportUniversally assumed by BI semantic layersOften needs manual join configuration
Hierarchy governanceAttributes repeat, updates touch more rowsHierarchy maintained in one place
Best fitAlmost all analytical modelsVery large dimensions with sparse, shared attribute sets

For the overwhelming majority of workloads on a modern platform, use the star. The storage argument for snowflaking was decisive on row-based systems in the 1990s and is close to irrelevant against columnar compression. Snowflake selectively where a hierarchy genuinely needs one governed source, or where a dimension has tens of millions of rows with attribute groups that are rarely queried together.

Two other approaches deserve honest treatment. Data Vault, with hubs, links, and satellites, is built for auditability and for source systems whose schemas change often. It is genuinely good at what it does, and it does not remove the need for a dimensional layer, because nobody wants to write reports against satellites. You end up building stars on top anyway. Inmon's approach, a normalized enterprise warehouse feeding dimensional data marts, is coherent and slow to deliver, which is why Kimball's bottom-up bus architecture with conformed dimensions won most of the market.

The newest contender is the wide table, sometimes called one big table: skip the joins, denormalize everything into a single wide fact with hundreds of columns, and let the columnar engine prune what it does not need. It performs well and it is genuinely fine for a single team's single use case. It fails at conformance. When four teams each build their own wide table, you are back to four definitions of active customer, which is the exact problem the warehouse was supposed to end.

Data warehouse modeling tools that earn their place

Data warehouse modeling tools fall into four groups, and most teams need one from each of the first two and can ignore the rest.

Transformation frameworks. dbt and SQLMesh are where the model actually lives now. Both give you version-controlled SQL, dependency graphs, tests, and documentation generated from the code. dbt snapshots handle Type 2. SQLMesh adds column-level lineage and virtual environments that make backfills cheaper. This category is not optional if more than one person touches the model.

Diagramming and design. dbdiagram, SqlDBM, Lucidchart, and erwin cover the range from a text file you regenerate in seconds to a governed enterprise repository. The honest advice: whatever you pick must be regenerable from the code, or it will be wrong within two sprints and nobody will trust it.

Automation for Data Vault. AutomateDV, VaultSpeed, WhereScape, and Coalesce generate the very repetitive SQL that Data Vault requires. Only relevant if you have chosen that pattern.

Semantic layers. Cube, LookML, and the dbt Semantic Layer define metrics once so that every consuming tool computes them the same way. This is the layer that makes conformed dimensions pay off in practice.

None of these tools will tell you your grain is wrong. They will faithfully build whatever you specify, including a fact table with two grains in it. Model review by a second human remains the only reliable control, alongside the automated checks described in Data Quality Tools: Catching Bad Data Before It Ships.

When data warehouse modeling is not worth the effort

Here is the part most guides on data warehouse architecture leave out. The full apparatus, a warehouse, ingestion pipelines, a transformation framework, a conformed dimensional model, a semantic layer, and a person who owns all of it, is justified by a specific set of conditions. Below a few hundred employees, most companies meet none of them.

Ask three questions honestly:

Will anyone actually ask a point-in-time question? Not "would it be nice to have history." Will a named person, with a real decision attached, ask what something looked like on a past date? If the answer is no, the single most expensive property of dimensional modeling is being bought for nothing.

Do your questions require joins your tools cannot do? Comparing forty million web events against two hundred thousand orders is warehouse work. Checking which accounts have an open invoice and a support escalation this week is not. That second question is answerable from live systems, and the choice of when a warehouse is genuinely required is worked through in Cloud Data Warehouse: When You Need One and When You Don't.

Do you have someone to own the model? A dimensional model without an owner drifts into an expensive archive in about two quarters. Connector schema changes go unnoticed, models accumulate contradictory filters, and the numbers become subtly wrong while still looking authoritative. Wrong numbers with a warehouse behind them are worse than missing numbers.

If you answered no to two of the three, the right move is the cheap middle path: snapshot your five most important tables daily so history exists when you need it, keep answering current-state questions directly from the tools that hold the data, and revisit the full model when a real question forces it.

Where Skopx fits, and where it does not

Skopx does not model your data, and it is not a warehouse. There is no schema to design, no grain to declare, no load to schedule. It connects to nearly 1,000 tools a company already uses, Gmail, Slack, Stripe, HubSpot, QuickBooks, Google Analytics and the rest, and answers questions by querying those systems live and citing the source it read.

That distinction is the whole point. For a large share of teams, the real problem is not schema design, it is that answering "which enterprise accounts have an open invoice past thirty days and no activity from their owner this month" takes forty minutes of tab switching. That question crosses three systems, needs current state, and needs no history at all. It does not need a star schema. It needs one place to ask.

Alongside chat, a morning brief summarizes what changed overnight across connected tools, and an insights engine surfaces anomalies and risks without anyone having to ask. Repeatable checks can be turned into workflows by describing them in chat. Skopx uses BYOK, meaning you bring your own AI key for any major model with zero markup on model usage, and plans are Solo at $5 per month and Team at $16 per seat per month. Details are on the pricing page.

Now the limits, stated plainly. Skopx cannot answer the territory question from the opening paragraph, because the CRM overwrote the old assignment and no live query can recover it. It will not compute a five-year cohort retention curve. It does not build dashboards, does not move or transform data, and is not a CRM. It has no governed semantic layer that finance can sign off on as the single definition of revenue. Every one of those is a legitimate reason to build a dimensional model, and if you need them, build one. If your list of unanswered questions is mostly about what is true right now across systems that already hold the data, modeling that data first is a long detour to an answer you could have had today.

For teams that do run both, the two coexist cleanly: the warehouse serves the historical and governed questions, and a query layer over live tools serves the operational ones. Reporting on the output of either is a separate skill, covered in How to Write a Data Insights Report (With a Template). If you are wiring source systems together yourself rather than buying a connector platform, Integrating APIs: A Practical Guide for Business Teams covers the failure modes that pipelines hit first.

Frequently asked questions

Is the star schema still relevant on modern columnar warehouses?

Yes, for the reason that had nothing to do with performance in the first place. The star's value is comprehensibility and conformance: one join per dimension, one definition of customer shared across processes. Columnar engines removed the storage argument for snowflaking and made wide tables viable, but neither of those addresses the problem of four teams disagreeing about what a customer is.

How do I choose the right grain?

Take the lowest atomic level the source system records, and declare it as one sentence with no "or" and no "except." If summarizing feels tempting, resist it. Aggregates can always be derived from atomic rows, and atomic rows can never be derived from aggregates.

Do I need surrogate keys if my source IDs are already unique?

If you plan to use Type 2 slowly changing dimensions, yes, because the natural key stops being unique the moment a dimension row has history. Surrogate keys also insulate you from a source system reusing IDs, from merging two systems with overlapping IDs, and they give you somewhere to put reserved rows for unknown and not-applicable members.

Star schema vs snowflake schema: which should I pick?

Start with a star and snowflake only where you have a specific reason: a very large dimension with sparse attribute groups, or a hierarchy that must be maintained in exactly one place for governance. Do not snowflake to save storage. Columnar compression already handled that.

Is The Data Warehouse Toolkit still worth reading?

The Data Warehouse Toolkit remains the clearest treatment of grain, fact table types, and slowly changing dimensions available, and those concepts have not aged. The infrastructure chapters are dated, since the book predates cloud warehouses and modern transformation frameworks. Read it for the modeling, get the tooling from current documentation.

How long does a first dimensional model take to build?

For one business process with three or four dimensions, on a platform that already has the raw data loaded, a competent analytics engineer can deliver something useful in two to four weeks. The multi-quarter timelines usually reported come from the ingestion, source-system negotiation, and definition arguments that surround the model rather than the modeling itself.

Share this article

Skopx Team

The Skopx engineering and product team

Related Articles

Stay Updated

Get the latest insights on AI-powered code intelligence delivered to your inbox.