Excelgoodies logo +44 (0)20 3769 3689

LEARN THIS HANDS ON

Power BI Reporting

. Live Online FILLING FAST
View all upcoming batches
Designing Incremental Refresh and Real-Time Dashboards in Power BI: Partitions, Policies, and Pitfalls

Designing Incremental Refresh and Real-Time Dashboards in Power BI: Partitions, Policies, and Pitfalls

Power BI incremental refresh and real-time dashboards let you keep reports fast while staying close to real-time data. This article shows how to design table partitions and refresh policies that actually work in production, and how to combine them with DirectQuery or push datasets for fresh, low-latency dashboards. If you want to go deeper into modelling and performance tuning, a structured course on advanced Power BI reporting skills is a strong complement to what follows.


1. What Incremental Refresh Really Buys You

Incremental refresh is not just "faster refresh". It changes how Power BI stores and updates data.

1.1 Core benefits

When designed well, incremental refresh gives you:

  • Smaller refresh windows: Only recent partitions are refreshed, not the entire history.
  • Stable historical data: Old partitions are locked and reused across refreshes.
  • Better gateway and source load: Less query volume against your database.
  • Predictable performance: You can reason about which partitions will be touched.

1.2 When it’s worth the effort

Incremental refresh is usually worth it when:

  • Fact tables are above a few hundred thousand rows and keep growing.
  • You have a clear date column that defines data recency.
  • Refresh duration is creeping up, or you’re hitting gateway/timeout issues.
  • The source system is sensitive to heavy repeated full loads.

If your model is small and refreshes in seconds, the overhead of incremental refresh may not be worth the complexity.


2. Partition Design: How to Slice Your Fact Tables

Incremental refresh creates partitions behind the scenes. Your job is to design the policy so those partitions make sense.

2.1 The three key knobs

When configuring incremental refresh in Power BI Desktop (on a table):

  1. Store rows in the last N (Range)
  2. Refresh rows in the last M (Increment)
  3. Optionally get real-time data with DirectQuery (Hybrid tables)

These map to partition behaviour:

  • Range defines how many partitions exist.
  • Increment defines which partitions are refreshed.
  • Hybrid decides whether the newest partition is DirectQuery.

2.2 Typical patterns

Common patterns for fact tables:

  • Daily grain, 2–3 years of data

    • Store: 3 years
    • Refresh: 7–30 days
    • Partitioning: daily partitions for recent periods, merged for older periods.
  • Hourly grain, 3–6 months of data

    • Store: 6 months
    • Refresh: 3–7 days
    • Partitioning: daily partitions, possibly merged monthly for older data.
  • Low-volume but long history

    • Store: 10+ years
    • Refresh: 1–7 days
    • Partitioning: monthly or yearly partitions.

The goal is to keep the number of partitions manageable while still isolating the “churn” into a small set of partitions.

2.3 Choosing the right date column

Always base incremental refresh on a column that:

  • Is not nullable.
  • Is monotonically increasing for new rows in practice (e.g., OrderDate, CreatedDate, PostingDate).
  • Does not change frequently after insert.

Avoid columns like LastModifiedDate for partitioning unless you know exactly how often they change. They can cause many partitions to be refreshed unnecessarily.


3. Implementing Incremental Refresh in Power Query

Incremental refresh relies on Power Query parameters and filter steps.

3.1 Define the parameters

In Power BI Desktop (Modeling > New Parameter), create two parameters:

  • RangeStart (Date/Time)
  • RangeEnd (Date/Time)

These names are case-sensitive for incremental refresh.

3.2 Filter your fact table

In Power Query, apply a filter on the date column using these parameters.

let
    Source = Sql.Database("SQLSERVER01", "SalesDW"),
    SalesFact = Source{[Schema="dbo", Item="FactSales"]}[Data],
    // Ensure DataDate is of type datetime
    ChangedType = Table.TransformColumnTypes(SalesFact, {{"DataDate", type datetime}}),
    FilteredRows = Table.SelectRows(
        ChangedType,
        each [DataDate] >= RangeStart and [DataDate] < RangeEnd
    )
in
    FilteredRows

Do not add additional filters on the same date column after this step; keep it clean so the Power BI service can fold it into your source queries.

3.3 Configure the policy

Back in the model view:

  1. Right-click your fact table > Incremental refresh and real-time data.
  2. Enable incremental refresh.
  3. Set:
    • Store rows in the last: 3 years (example)
    • Refresh rows in the last: 7 days (example)
  4. Optionally enable Get the latest data in real time with DirectQuery (hybrid tables).

Remember: the incremental logic only applies once the dataset is published to the service and a refresh runs there. The Desktop refresh still loads all data.


4. Hybrid Tables: Incremental + Real-Time

Hybrid tables combine:

  • Import partitions for historical and recent data.
  • DirectQuery partition for the very latest slice (e.g., today or last few hours).

This is the bridge between incremental refresh and real-time dashboards.

4.1 When to use hybrid tables

Hybrid tables are useful when:

  • You need sub-15-minute freshness for a subset of data.
  • The source can handle DirectQuery load (indexes, concurrency, etc.).
  • You still want the performance of Import for the bulk of your history.

4.2 Designing the real-time window

Typical patterns:

  • Daily DirectQuery window: Today’s data via DirectQuery, older data via Import.
  • Rolling X hours: Last 1–4 hours via DirectQuery; everything older imported.

You control this with the refresh policy and your date column. For example, if you:

  • Store 3 years.
  • Refresh last 7 days.
  • Enable DirectQuery for the latest partition.

Then the latest partition (usually “today”) is served via DirectQuery; the previous days are Import.

4.3 Impact on DAX and visuals

From a report author perspective, hybrid tables behave like any Import table. But keep in mind:

  • Queries touching only historical data will be fast (Import).
  • Queries touching today’s data will hit DirectQuery and depend on source performance.
  • Heavy measures or complex joins can magnify DirectQuery latency.

You may want to:

  • Simplify measures that are often filtered to “Today”.
  • Pre-aggregate some metrics in the source for the DirectQuery partition.

5. Real-Time Dashboards: Beyond Incremental Refresh

Incremental refresh and hybrid tables give you near real-time. For truly real-time dashboards (seconds-level latency), you have three main options:

  1. Streaming datasets (push-only, limited modelling).
  2. Push datasets (can be used as regular models, but data is pushed via API).
  3. DirectQuery against a streaming or frequently-updated source.

5.1 Push vs streaming datasets

Streaming datasets:

  • Optimised for high-frequency data.
  • Limited visuals and no relationships or complex DAX.
  • Good for IoT-style telemetry, quick monitoring tiles.

Push datasets:

  • Support a full model (relationships, measures, etc.).
  • Data is written via REST API or Power Automate.
  • Dashboard tiles can be set to refresh automatically when new data arrives.

For most BI scenarios, push datasets are more flexible than pure streaming.

5.2 Example: Pushing real-time rows

You can push new rows into a dataset from an external process. Example in Python using the Power BI REST API (simplified):

import requests
import json

access_token = "<ACCESS_TOKEN>"

url = "https://api.powerbi.com/beta/<tenant-id>/datasets/<dataset-id>/tables/RealTimeFact/rows"

headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {access_token}"
}

rows = [{
    "EventTime": "2026-09-23T10:15:00Z",
    "MachineId": "M-101",
    "Status": "Running",
    "OutputQty": 120
}]

payload = json.dumps({"rows": rows})

response = requests.post(url, headers=headers, data=payload)
response.raise_for_status()

This is typically wired up in:

  • ETL jobs for micro-batches.
  • Event-driven functions (Azure Functions, Logic Apps).
  • On-prem services via gateways.

5.3 Combining push datasets with a core model

A common pattern:

  • Core model: Large historical dataset with incremental refresh and hybrid tables.
  • Real-time dataset: Small push dataset capturing the last minutes/hours.

You then:

  • Build two reports and pin visuals to a single dashboard, or
  • Use composite models to combine real-time and historical data in one semantic layer.

Be explicit about which visuals are "live" and which are historical so users understand the behaviour.


6. Practical Partition and Policy Patterns

Let’s outline a few concrete designs you can adapt.

6.1 Daily sales with near real-time today

Scenario: Retail sales, millions of rows/day, need near real-time for today.

  • Incremental policy:
    • Store: 3 years.
    • Refresh: 7 days.
    • Enable DirectQuery for latest partition (hybrid).
  • Real-time behaviour:
    • Today’s sales via DirectQuery.
    • Last 6 days via Import (refreshed daily or several times a day).
    • Older data frozen.

Notes:

  • Index OrderDate in the source.
  • Consider a persisted aggregate view for today’s metrics to keep DirectQuery simple.

6.2 Operational metrics with second-level latency

Scenario: Manufacturing KPIs, need updates every few seconds on a wallboard.

  • Incremental policy on core fact:
    • Store: 12 months.
    • Refresh: 1 day.
    • No hybrid (all Import).
  • Real-time dataset:
    • Push dataset with last 10–60 minutes of events.
    • Wallboard visuals built on push dataset.
  • Dashboard:
    • Historical trend tiles from core model.
    • Live status tiles from push dataset.

Notes:

  • Keep push dataset schema narrow and low-volume.
  • Use retention policies (e.g., only keep last X minutes in the push dataset).

6.3 Finance with monthly closes and late adjustments

Scenario: Financial postings with back-dated adjustments.

  • Incremental policy:
    • Store: 10 years.
    • Refresh: 2 months.
    • No hybrid (DirectQuery often not ideal for complex finance models).
  • Partitioning behaviour:
    • Recent months refreshed daily to pick up adjustments.
    • Older months frozen.

Notes:

  • Use PostingDate or DocumentDate consistently for partitioning.
  • If adjustments can hit any period, consider a second "adjustments" fact table instead of refreshing everything.

7. Common Pitfalls and How to Avoid Them

7.1 Too many tiny partitions

  • Symptom: Many partitions, slow metadata operations, overhead in the service.
  • Cause: Policies that create hourly partitions over several years, or very granular date columns.
  • Fix: Use daily or monthly partitions; let Power BI merge older partitions.

7.2 Non-foldable filters

  • Symptom: Incremental refresh behaves like a full refresh.
  • Cause: Transformations in Power Query that break query folding before the date filter.
  • Fix:
    • Keep the RangeStart/RangeEnd filter as early as possible.
    • Avoid custom functions or non-foldable steps before the filter.

7.3 Wrong date column

  • Symptom: Old partitions keep refreshing; refresh takes longer than expected.
  • Cause: Using a column that changes frequently or doesn’t match your business definition of "new" data.
  • Fix: Switch to a stable, insertion-based date column for incremental refresh.

7.4 Overusing DirectQuery

  • Symptom: Real-time visuals are slow, time out, or load the source heavily.
  • Cause: Complex DAX measures and joins over DirectQuery tables.
  • Fix:
    • Use DirectQuery only where you truly need it (latest partition or small real-time tables).
    • Pre-aggregate in the source.
    • Simplify measures for DirectQuery parts.

8. One Change to Make This Week

Pick your largest fact table and redesign its refresh policy:

  1. Identify a stable date column and create RangeStart/RangeEnd filters.
  2. Set a Store window that matches your real business need (not “forever just in case”).
  3. Set a Refresh window that covers the period where data actually changes.

Deploy it, monitor refresh duration and source load for a week, and adjust. Getting this one table right often unlocks the performance headroom you need to safely add a real-time layer on top.

Power BI

New

Next Batches Now Live

Power BIPower BI
SQLSQL
Power AppsPower Apps
Power AutomatePower Automate
Microsoft FabricMicrosoft Fabrics
AzureAzure Data Engineering
Explore Dates & Reserve Your Spot → Reserve Your Spot →