MICROSOFT POWER BI • DATA MODELING

Fact vs. Dimension Tables — Distinguish fact tables vs dimension tables (conceptual)

Understanding the two fundamental table types that form the backbone of every analytical data model.

Historical Context & Motivation

The distinction between fact tables and dimension tables did not emerge with Power BI — it is rooted in decades of research on how organizations should structure data for analytical querying. In the 1960s and 1970s, relational database theory focused on online transaction processing (OLTP), where highly normalized schemas minimized redundancy at the expense of query complexity. As businesses accumulated vast repositories of historical data, a new paradigm was needed — one optimized not for writing individual transactions, but for reading and aggregating large volumes of records. This need gave rise to the field of dimensional modeling, which treats data as a combination of measurable events and the descriptive contexts surrounding them.

1970
Codd's Relational Model
E. F. Codd published "A Relational Model of Data for Large Shared Data Banks," establishing the theoretical foundation for relational databases and normalization — the standard for OLTP systems.
1988
Kimball's Dimensional Modeling
Ralph Kimball introduced dimensional modeling, proposing that analytical databases should be structured around star schemas composed of fact and dimension tables, optimized for human understandability and query performance.
1996
The Data Warehouse Toolkit
Kimball's seminal book codified best practices for building dimensional models, establishing fact and dimension tables as the canonical building blocks of data warehouses across industries.
2009
VertiPaq & Power Pivot
Microsoft introduced the VertiPaq columnar engine in Power Pivot (later integrated into Power BI), bringing dimensional modeling directly to business analysts with in-memory compression and DAX calculations.
2015–Present
Power BI Ecosystem
Power BI Desktop and Service mature into the dominant self-service BI platform, with star schema design — fact and dimension tables connected by relationships — at the core of every performant data model.

The central question that dimensional modeling answers is deceptively simple: how should we organize data so that analytical queries are both fast and intuitive? The answer hinges on cleanly separating quantitative measurements from the descriptive attributes that give those measurements meaning. This separation is the conceptual foundation we will explore throughout this lesson.

Core Principles & Definitions

At its core, dimensional modeling divides every dataset into two categories of tables. A fact table records measurable events or transactions — the "what happened" of your business. Each row typically represents a single event such as a sale, a shipment, or a web click, and the table's numeric columns (called measures) are the values you aggregate in reports: revenue, quantity, duration. A dimension table, by contrast, stores the descriptive context — the "who, what, where, when, why, and how" that qualifies each event. Dimension tables contain textual or categorical attributes such as product name, customer region, or calendar month, which analysts use to slice, filter, and group the facts.

1

Fact Tables Store Events

Each row in a fact table captures a discrete business event or measurement. Columns are primarily foreign keys (linking to dimensions) and numeric measures (values to aggregate).
2

Dimension Tables Store Context

Dimension tables provide the descriptive attributes — product names, customer demographics, geographic regions — used to filter, group, and label the numeric facts in reports and dashboards.
3

Grain Defines Granularity

The grain of a fact table specifies what a single row represents (e.g., one line item per order). Choosing the correct grain is the most critical design decision in dimensional modeling.
4

Star Schema Topology

In a star schema, a central fact table connects to multiple surrounding dimension tables via one-to-many relationships, forming a star-like topology. Power BI's engine is optimized for this pattern.
KEY TAKEAWAY
Think of a fact table like a log file — it records every event with timestamps and numeric values but minimal human-readable context. Dimension tables are like lookup dictionaries that translate cryptic foreign key IDs into meaningful labels. Just as a compiler resolves symbol references via a symbol table, a BI engine resolves fact-table keys through dimension tables to produce readable, filterable reports.

Visual Explanation — The Star Schema

The central Sales fact table holds foreign keys and measures. Four dimension tables — Product, Customer, Date, and Store — radiate outward, each connected by a one-to-many relationship on their respective primary/foreign key pair. This topology is why the design is called a star schema.

Observe the asymmetry between the two table types. The fact table is typically tall and narrow — it may contain millions or even billions of rows (one per transaction), but its column count is modest: mostly integer foreign keys and a handful of numeric measures. Dimension tables, by contrast, are wide and short — a Product dimension might have only 5,000 rows (one per distinct product) but 30 or more descriptive columns (name, category, subcategory, brand, color, weight, introduction date, and so on). This structural difference directly influences how Power BI's VertiPaq engine compresses and indexes each table, and it is the reason star schemas consistently outperform flat, denormalized tables in analytical workloads.

How It Works — Relationships & Filter Flow

In Power BI, the relationship between a dimension table and a fact table is always a one-to-many (1:N) relationship where the dimension table sits on the "one" side (each row has a unique primary key) and the fact table sits on the "many" side (its foreign key column may repeat the same dimension key across thousands of rows). This relationship defines the filter propagation direction: by default, filters flow from the dimension side to the fact side. When a user selects "Electronics" in a slicer connected to the Product dimension, that filter propagates through the relationship to the fact table, restricting aggregations to only those rows where ProductKey matches an electronics product.

Filters originate from a dimension table and propagate through the relationship to the fact table. The VertiPaq engine resolves matching keys and then computes the requested aggregation. This unidirectional flow from dimension to fact is the default behavior in Power BI.

This unidirectional filter flow is not merely a UI convenience — it reflects a deep design principle. Because dimension tables have unique keys and fact tables have repeating keys, the engine can efficiently hash-join the filtered dimension keys against the fact table's compressed column segments. Bidirectional filtering (where the fact table can also filter a dimension table) is possible but should be used sparingly, as it can introduce ambiguity, degrade performance, and create circular dependency risks in more complex models.

💡 Cross-Filter Direction
In Power BI's Model view, each relationship has a cross-filter direction property: Single (dimension → fact, the default and recommended setting) or Both (bidirectional). For a clean star schema, keep the default single direction.

Detailed Breakdown — Fact Types & Dimension Characteristics

Types of Fact Tables

Not all fact tables are created equal. The three canonical types — transaction facts, periodic snapshot facts, and accumulating snapshot facts — capture events at different temporal resolutions. A transaction fact table records each individual event (e.g., every line item in every order). A periodic snapshot captures the state of a measure at regular intervals (e.g., daily inventory levels). An accumulating snapshot tracks the lifecycle of a process across multiple milestones (e.g., an order moving through stages: placed → shipped → delivered → returned).

Three canonical fact table types classified by grain and growth pattern
Fact Table TypeGrainRow GrowthExample
TransactionOne row per eventUnbounded — grows with activityIndividual retail POS line items
Periodic SnapshotOne row per entity per periodPredictable — one row per periodDaily account balances
Accumulating SnapshotOne row per entity lifetimeFixed — rows updated, not appendedOrder fulfillment pipeline

Characteristics of Dimension Tables

Dimension tables share several structural hallmarks. Each has a surrogate key — typically an integer primary key generated during the ETL process to uniquely identify each row. Dimension tables are denormalized: rather than splitting Product and ProductCategory into two normalized tables with a foreign key, you flatten them into one wide table so the BI engine can resolve attributes in a single lookup. This deliberate redundancy trades storage efficiency for query speed — a classic time–space trade-off that should feel familiar from algorithm design.

  • Surrogate key: A synthetic integer primary key, independent of source system identifiers, enabling consistent joins and historical tracking.
  • Natural key: The original business identifier (e.g., SKU or employee ID) retained as an attribute column for reference but not used as the join key.
  • Descriptive attributes: Text or categorical columns (ProductName, Color, Size) used in slicers, axes, and legends of Power BI visuals.
  • Hierarchies: Columns that form a drill-down path (e.g., Year → Quarter → Month → Day in a Date dimension).

Worked Example — Designing a Star Schema for an E-Commerce Dataset

Suppose you are given a flat CSV export from an e-commerce database containing the columns: OrderID, OrderDate, ProductName, Category, Subcategory, CustomerName, CustomerEmail, City, State, Country, Quantity, UnitPrice, Discount, TotalAmount. Your task is to decompose this into a proper star schema within Power BI.

Decomposing a Flat Table into Fact and Dimension Tables
1
Step 1 — Identify the GrainThe first question to answer: what does one row represent? In this dataset, each row is a single line item within an order. An order may span multiple products, so the grain is one product per order. This becomes the grain of our fact table.
Grain: one line item per order
2
Step 2 — Separate Measures from AttributesScan each column and classify it as either a numeric measure (something you would SUM, AVG, or COUNT) or a descriptive attribute (something you would filter, group, or label by). Quantity, UnitPrice, Discount, and TotalAmount are measures. ProductName, Category, Subcategory, CustomerName, CustomerEmail, City, State, Country, and OrderDate are attributes.
Measures: Quantity, UnitPrice, Discount, TotalAmount. Attributes: everything else.
3
Step 3 — Group Attributes into DimensionsCluster related attributes into logical dimension tables. ProductName, Category, and Subcategory belong to a Product dimension. CustomerName, CustomerEmail, City, State, and Country form a Customer dimension. OrderDate maps to a Date dimension (typically a pre-built calendar table with Year, Quarter, Month, DayOfWeek, and other temporal attributes).
Three dimensions identified: DimProduct, DimCustomer, DimDate.
4
Step 4 — Create Surrogate KeysGenerate unique integer surrogate keys for each dimension table (ProductKey, CustomerKey, DateKey). In Power Query, you can add an Index Column starting at 1 for Product and Customer after removing duplicates. For the Date dimension, the integer key is commonly the date in YYYYMMDD format (e.g., 20240315).
Surrogate keys: ProductKey (INT), CustomerKey (INT), DateKey (INT as YYYYMMDD).
5
Step 5 — Construct the Fact TableThe fact table retains only the foreign keys (ProductKey, CustomerKey, DateKey) and the numeric measures (Quantity, UnitPrice, Discount, TotalAmount). All descriptive text columns have been moved to dimension tables. In Power BI's Model view, create one-to-many relationships from each dimension's primary key to the corresponding fact table foreign key.
Result: FactSales (ProductKey, CustomerKey, DateKey, Quantity, UnitPrice, Discount, TotalAmount) with three relationships to DimProduct, DimCustomer, and DimDate.

Fact vs. Dimension — Head-to-Head Comparison

Side-by-side comparison of fact and dimension table characteristics
CharacteristicFact TableDimension Table
PurposeStores measurable events / metricsStores descriptive context / attributes
Typical Row CountMillions to billionsHundreds to low millions
Typical Column CountNarrow (5–15 columns)Wide (10–50+ columns)
Key Column RoleForeign keys referencing dimensionsPrimary (surrogate) key — unique per row
Data TypesMostly integers, decimals, currencyMostly text, dates, booleans
AggregationColumns are summed, averaged, countedColumns are used to filter, group, slice
NormalizationAlready minimally structuredDeliberately denormalized (flat)
Filter Role in Power BIReceives filters (many side)Originates filters (one side)
🔑 DESIGN HEURISTIC
If you are unsure whether a column belongs in a fact or a dimension table, apply this test: would you SUM or AVG this column in a report? If yes, it is a measure and belongs in the fact table. Would you put this column in a slicer, legend, or axis label? If yes, it is an attribute and belongs in a dimension table. This heuristic resolves the classification for the vast majority of columns you will encounter.

Connection to Advanced Theory — Snowflake, Galaxy, and Beyond

The star schema is the simplest and most performant dimensional topology, but it is not the only one. As data models grow in complexity, two extensions arise. The snowflake schema normalizes dimension tables by splitting hierarchical attributes into sub-dimension tables (e.g., a Product dimension linked to a separate Category dimension). While this reduces storage via deduplication, it increases the number of joins required at query time and complicates the model for business users — Power BI's documentation explicitly recommends avoiding snowflaking in most scenarios. The galaxy schema (also called a fact constellation) involves multiple fact tables sharing conformed dimensions, which is essential when modeling complex business domains with several distinct processes (e.g., Sales facts and Inventory facts both referencing the same Product and Date dimensions).

Comparison of dimensional schema topologies
Schema TypeDimension StructureQuery ComplexityPower BI Recommendation
StarFully denormalized dimensionsLow — single hop from fact to dimensionStrongly recommended
SnowflakeNormalized dimensions with sub-dimensionsMedium — multi-hop joins requiredGenerally discouraged; flatten in Power Query
Galaxy / ConstellationShared (conformed) dimensions across multiple factsVaries — depends on number of fact tablesAppropriate for complex multi-process domains

Looking forward, as you progress into advanced data engineering and modeling, you will encounter concepts like slowly changing dimensions (SCDs) — strategies for handling dimension attribute changes over time (Type 1 overwrites, Type 2 adds versioned rows, Type 3 adds previous-value columns). You will also encounter role-playing dimensions where a single physical dimension table (like a Date table) participates in multiple relationships to the same fact table under different roles (OrderDate, ShipDate, DeliveryDate). These advanced patterns all build on the foundational distinction between facts and dimensions that this lesson has established.

Practice Problems

PROBLEM 1CONCEPTUAL
A colleague argues that the Customer table in your Power BI model is a fact table because it contains a "TotalLifetimeSpend" column. Explain why this classification is incorrect, and clarify where TotalLifetimeSpend should reside in a proper star schema.
PROBLEM 2BASIC CALCULATION
You have a flat table with 500,000 transaction rows. There are 2,000 unique products, 10,000 unique customers, and 730 unique dates (two years of daily data). After decomposing into a star schema, how many total rows exist across the fact table plus all three dimension tables? What percentage reduction in total cell count does the star schema achieve compared to the flat table if the flat table has 14 columns and the star schema has: FactSales (6 columns), DimProduct (5 columns), DimCustomer (6 columns), DimDate (8 columns)?
PROBLEM 3INTERMEDIATE
You are building a Power BI model for a hospital. The source data includes a table with columns: AdmissionID, PatientName, PatientDOB, DiagnosisCode, DiagnosisDescription, DoctorName, DoctorSpecialty, AdmissionDate, DischargeDate, RoomNumber, DailyCharge, InsurancePaid, PatientPaid. Design a star schema: identify the fact table (with its grain), the dimension tables, and which columns go where. Explain any design decisions.
PROBLEM 4APPLIED
A data engineering team delivers a Power BI model where a single large table called 'AllData' contains 50 columns and 20 million rows. Reports are running slowly, and the PBIX file is 2.4 GB. Describe the systematic steps you would take to refactor this into a star schema, including specific Power Query transformations, and explain why each step should improve performance.
PROBLEM 5CRITICAL THINKING
Consider a scenario where a 'ProductPrice' changes frequently — sometimes multiple times per day. Discuss whether UnitPrice should be stored in the fact table, the Product dimension table, or a separate structure. Analyze the trade-offs of each approach in terms of historical accuracy, model complexity, query performance, and DAX measure authoring.

Lesson Summary

Every well-designed Power BI data model rests on the fundamental distinction between fact tables and dimension tables. Fact tables are tall, narrow repositories of numeric measures and foreign keys, recording individual business events at a defined grain. Dimension tables are wide, short collections of descriptive attributes — the who, what, where, when, and why — connected to the fact table via one-to-many relationships that form a star schema.

This architecture enables filter propagation from dimensions to facts, allowing users to slice and aggregate data intuitively. Fact tables come in three types — transaction, periodic snapshot, and accumulating snapshot — while dimension tables are characterized by surrogate keys, denormalized structure, and drill-down hierarchies. Mastering this conceptual separation is the gateway to building performant, maintainable models in Power BI and the broader ecosystem of analytical data platforms.

Varsity Tutors • Microsoft Power BI • Fact vs. Dimension Tables