25–30% of exam

Module 2 — Data Modeling

A Power BI semantic model determines how business entities relate, how filters propagate, how calculations behave, and how efficiently the engine can answer report queries. This module builds the reasoning needed to design a clean star schema, choose the right grain, manage date roles, select the correct calculated object, and optimize model performance.

Your progress is saved on this browser.
0/160 questions completed
Concept 1

Star schema, fact/dimension design & grain

A strong Power BI model begins with two decisions: what each table represents and what one row in each fact table means. These decisions define the grain of the model and determine whether later measures can answer the required questions correctly.

A fact table normally contains measurable business events or snapshots—for example, one row per sales transaction, one row per support ticket, or one row per daily inventory snapshot. A dimension table contains descriptive attributes used to filter and group those facts, such as Product, Customer, Date, Store or Employee.

Power BI models work best when these tables are organized into a star schema. Dimension tables sit around a central fact table and connect to it through keys. The dimension side normally contains one unique row per entity, while the fact table can contain many rows for the same dimension key.

Grain: the precise meaning of one row in a table. “One row per transaction line” is a grain. “Sales data” is not precise enough.

Why grain matters

  • If the fact table is already aggregated to one row per month and product, you cannot later count individual transactions because that detail no longer exists.
  • If you need distinct customers, transaction counts or analysis by transaction attributes, the fact table must retain the required level of detail.
  • Different business processes often deserve separate fact tables rather than being forced into one table with inconsistent grain.
  • Keys used to relate facts to dimensions should identify the intended dimension row consistently. Surrogate keys are common in warehouse designs because they separate model relationships from changing business identifiers.

Many-to-many business relationships

Some entities genuinely relate many-to-many—for example, one consultant can work on many projects and one project can have many consultants. A bridge table can store the valid consultant-project combinations and connect both dimensions through controlled one-to-many relationships. This is usually clearer than relying on an ambiguous direct many-to-many relationship.

Example: A retail sales fact table at “one row per product on each receipt” can support quantity, revenue, product, store, customer and transaction analysis. If you first aggregate it to “one row per store per month,” you lose receipt-level questions such as average basket size and transaction count.
Exam gotcha: A DAX measure aggregates at query time. Power Query Group By changes the physically stored grain.
Concept 2

Cardinality, cross-filter direction & filter propagation

Relationships allow filters to move between tables. To reason about a Power BI model, always ask three questions: what is the cardinality, which direction can the filter travel, and is the relationship active?

In a normal star schema, a dimension has a unique key and is on the one side of a one-to-many relationship. The fact table contains repeated foreign keys and is on the many side. This relationship lets a filter such as Product Category = Bikes restrict the fact rows that contribute to a measure.

Cross-filter direction

With single-direction filtering, filters normally travel from the dimension to the fact table. This direction is predictable, efficient and is the default best practice for most star schemas.

Bidirectional filtering allows filters to travel in both directions. It can solve specific modeling requirements, but it also makes the model harder to reason about and can create multiple possible filter paths. When two paths can carry the same filter between tables, Power BI can encounter ambiguity.

Filter propagation example: Customer → Sales ← Product. If both relationships are single direction from the dimensions to Sales, choosing a customer country filters Sales, but that filter does not travel backward from Sales into Product. Therefore, a Product slicer does not automatically shrink to only products purchased by that country.

Cardinality terminology

  • One-to-many (1:*) is the standard dimension-to-fact pattern.
  • One-to-one (1:1) requires unique values on both sides and is less common in analytical models.
  • Many-to-many (*:*) allows duplicates on both sides but should be used deliberately because filter behavior can be harder to understand.
  • Column cardinality means the number of distinct values stored in a column. It is a storage/model-optimization concept and is different from relationship cardinality.

Before creating a one-to-many relationship, make sure the key on the one side is truly unique. If it is not, correct the dimension design or choose a modeling pattern that represents the real relationship.

Exam gotcha: Do not turn on bidirectional filtering merely to make slicers reduce one another unless the business requirement justifies it.
Concept 3

Date tables, active/inactive relationships & role-playing dimensions

Time intelligence and date filtering are much more reliable when a model contains a dedicated Date dimension rather than relying only on date columns scattered through fact tables.

A good Date table contains one row for every date in the required range and usually adds attributes such as Year, Quarter, Month Name, Month Number and Year-Month. The date column used as the primary date key should be unique and nonblank. For classic time-intelligence scenarios, the range should be continuous so functions can reason about adjacent periods correctly.

Sorting date labels

Text labels sort alphabetically unless you give Power BI a numeric or sequential sort column. For example, Month Name should be sorted by Month Number so January appears before February. A Month-Year label such as “Jan 2026” should use a YearMonth key such as 202601; sorting only by Month Number would mix months from different years.

Multiple date roles

A fact table often contains more than one date, such as Order Date, Ship Date and Invoice Date. Power BI can store several relationships between the same Date table and fact table, but only one can be active at a time. The active relationship is used automatically for normal filtering.

USERELATIONSHIP() tells CALCULATE() to use an existing inactive relationship for a particular calculation. This is useful when one Date slicer should usually filter Order Date but a specific measure must calculate by Ship Date.

Role-playing dimension: multiple logical uses of the same type of dimension. If users need independent Order Date and Ship Date slicers at the same time, separate Date tables—such as Order Date and Ship Date—make the two roles explicit and independently filterable.
Example: With one shared Date table, a user cannot independently select “Orders in January” and “Shipments in February” using two slicers from that same table. Separate role-playing date dimensions solve that requirement cleanly.
DAX
Shipped Sales =
CALCULATE (
    [Total Sales],
    USERELATIONSHIP ( 'Date'[Date], Sales[ShipDate] )
)
  • [Total Sales] is the existing base measure. Reusing a base measure keeps the business aggregation logic in one place.
  • CALCULATE reevaluates that measure under a modified filter/relationship context rather than changing the stored model relationship permanently.
  • USERELATIONSHIP ( 'Date'[Date], Sales[ShipDate] ) identifies an existing inactive relationship and activates it for this calculation.
  • During this evaluation, the ShipDate path is used to propagate the Date filter. Other unrelated filters, such as Product or Region, continue to apply.
  • When the calculation finishes, the model still has the same active/inactive relationship configuration; USERELATIONSHIP is local to the expression.
Exam gotcha: USERELATIONSHIP solves a calculation-by-alternate-date problem; it does not make one Date table behave like two independent slicers.
Concept 4

Measures, calculated columns, calculated tables & quick measures

Power BI offers several ways to create derived logic, and the correct choice depends on whether the result is stored or calculated at query time, whether it is row-level or aggregate, and whether users need to group or filter by it.

ObjectHow it behavesTypical use
MeasureCalculated at query time in the current filter context; returns a scalar result.Sales, margin %, customer count, YTD revenue.
Calculated columnCalculated row by row during model processing and stored in the model.Band, classification, label or attribute needed on rows/axes/slicers.
Calculated tableA table created by DAX during model processing.Special model tables that must be derived from existing model data.

Measures are usually the preferred choice for analytical calculations because the same measure can return different results for different report filters. A measure such as [Total Sales] can show one value for the whole report, another by product, and another by month without storing separate results.

Calculated columns are useful when every row needs a stable category that users must place in a slicer, row header or axis. Because the values are stored, high-cardinality calculated columns can increase model size. If a static transformation can be performed in the source or Power Query, doing it before load is often more efficient and keeps preparation logic together.

Calculated tables can be useful for model structures created from existing model data, but source-system or Power Query transformations are generally preferable when they can produce the same stable table earlier in the pipeline.

Quick measures

Quick measures use a guided interface to generate DAX for common calculations. They can save time, but for PL-300 you should still understand the generated DAX. The exam can test the underlying calculation behavior even if the feature created the formula for you.

Example: “Profit Margin %” should normally be a measure because it must recalculate for whichever filters are active. “Customer Age Band” may be a calculated column if users must put the band directly on a chart axis or slicer.
Exam gotcha: A measure is not a stored categorical column and therefore is not normally a slicer field.
Concept 5

Model properties & performance optimization

Power BI performance depends not only on DAX but also on how much data the model stores and how efficiently VertiPaq can encode it. Good model optimization starts by removing data the report does not need and by avoiding unnecessary detail.

VertiPaq is a columnar storage engine. It compresses repeated values very efficiently, so columns with relatively few distinct values usually compress well. High-cardinality columns—especially long text, unique transaction identifiers and precise timestamps—can consume much more memory because they contain many distinct values.

Practical model optimization

  • Remove unused columns before load. A hidden column still occupies model memory; hiding only changes the authoring experience.
  • Remove rows that are outside the analytical requirement when it is safe to do so.
  • Reduce unnecessary granularity. If the report only analyzes dates, storing second-level timestamps may add cardinality without analytical value.
  • Use appropriate data types and precision. Smaller, simpler representations can improve compression.
  • Set meaningful names, formatting and data categories so report authors use fields correctly.
  • For numeric identifiers such as Product ID, use Don't summarize when summing the number has no business meaning.

Diagnosing performance

Performance Analyzer in Power BI Desktop records how long visuals take to execute, including DAX query time and rendering-related activity. Use it when you need to identify which report visuals are slow before deciding how to optimize them.

DAX query view allows you to write and run DAX queries against the model. It is useful for inspecting model results and investigating calculations. A slow report can come from inefficient measures, poor relationship design, too many visuals, source latency in DirectQuery, or an oversized model—not just from one DAX formula.

Example: Removing an unused free-text comment column that is almost unique across 100 million fact rows can save far more model memory than hiding the column or changing its display name.
Exam gotcha: Hiding a column improves the field list but does not reduce VertiPaq storage and is not security.