Power BI Report Performance Troubleshooting - A Field Guide From Real Engagements
The slow report ticket is the most common ticket we get inside Power BI engagements. It usually starts with something like "the finance dashboard takes 40 seconds to open in the morning" or "the sales report is fine for me but our Perth team says it's unusable". By the time it lands with us, the internal BI team has often spent days swapping visuals and rebuilding models without ever finding the real cause.
Microsoft published a troubleshoot report performance guide that walks through their official flowchart for diagnosing this. It's good. Genuinely. But the flowchart is necessarily generic, and the experience of running it on a real client tenant has some texture that the docs don't capture. This post is what I'd tell a junior consultant before they started their first performance investigation.
Why the flowchart even exists
Power BI performance problems have at least six different root causes, and the right fix for each is wildly different. If you guess wrong, you can spend a week rebuilding a semantic model when the real problem was a misconfigured on-premises gateway. We've seen it happen.
The Microsoft flowchart forces you to ask a few branching questions before you start changing anything:
- Is the report on a Premium or Fabric capacity, or on shared?
- Does the problem happen at specific times of day?
- Does the problem happen in specific geographic regions?
- Does the problem happen on specific devices or browsers?
Those four questions split the problem space into manageable chunks. The actions at each terminator point to a different fix. Capacity management, architecture change, gateway tuning, DAX optimisation, or a support ticket.
Read it once before you start. It will save you from doing the wrong work confidently.
Premium capacity is where the diagnostic data lives
If the report is on Premium or Fabric capacity, you have an actual tool to work with. The Fabric Capacity Metrics app gives you a 14-day view of CU usage per item, including throttling events and overage. This is the single best signal we get for "is this report slow because the capacity is overloaded, or for some other reason".
What we look for first in a Premium investigation:
- CU spikes that line up with report load times
- Throttling or rejection events
- A single noisy item consuming most of the capacity
- Background versus interactive split
If the capacity is constantly over 80% during business hours, the report isn't really the problem. The capacity is. Either someone is running heavy refreshes during peak query time, or you've outgrown your SKU. We had a client on F32 whose finance team kept complaining about morning slowness. The metrics app showed three refresh jobs starting at 8:15am while the executives were trying to open dashboards. Moving those refreshes to 5am fixed 80% of the perceived performance problem without anyone touching a DAX measure.
If the capacity has plenty of headroom but specific reports are still slow, the cause is inside the report. Different problem, different tools. Go to Performance Analyzer.
Shared capacity is harder to diagnose
If the client is on Pro and reports are on shared capacity, you can't see capacity health at all. You're flying blind on the infrastructure side, which forces you to triangulate from user behaviour instead.
The first question I ask is whether the slowness has a time pattern. Morning peak, end of month, particular weekday. If it does, and lots of people are hitting the report at once, you have a query throughput problem. The honest answer here is usually that shared capacity isn't built for that volume of concurrent queries. Migrating the semantic model to Premium or to Azure Analysis Services solves it. We don't love telling clients they need to buy more licensing, but a $5k/month Premium capacity that lets the sales team open the dashboard in 3 seconds instead of 30 has paid for itself by Wednesday.
The second question is whether the slowness is geographic. If only the Perth office complains and the Sydney office is fine, you've almost certainly got a data gateway located too far from the data source, or you've got a Direct Query model with a remote source and high network latency. Architecture problem, not a model problem. We've seen Australian businesses with a gateway sitting in a Sydney data centre talking to a SQL Server in Melbourne, and the latency added 15 seconds per visual load. Moving the gateway closer to the source, or rearchitecting to Import mode, fixed it.
The third question is whether the slowness is on specific devices or browsers. If it's only on Edge on Windows 10, you raise a Microsoft support ticket. It happens occasionally. Don't waste a week of consulting time on a known browser bug.
If none of the patterns apply and the slowness is uniform across time, geography, and device, the problem is almost certainly inside the report or the model.
Performance Analyzer is the underused hero
Power BI Desktop ships with Performance Analyzer, which records the timing breakdown for every visual on the page. DAX query time, visual display time, other. Most internal BI teams know it exists but treat it as a curiosity. It should be the first thing you open when investigating a slow report.
The thing it tells you that nothing else does is whether the time is being spent in the engine (DAX) or in the browser (rendering). If your visual is taking 8 seconds and 7 of those are DAX, the answer is to fix the measure. If 7 of those are rendering, the answer is to reduce the number of points the visual is trying to draw, or pick a different visual.
We did a performance review for a mid-sized Australian business intelligence engagement last year where the client had spent three weeks rewriting their financial model because reports were slow. Performance Analyzer showed that the DAX queries were finishing in 200ms. The slow part was a custom visual that was rendering 12,000 points on a scatter plot. They didn't have a model problem. They had a visual choice problem. Two days of work to swap visuals and use a top-N filter, and the page loaded in under 2 seconds.
The other thing Performance Analyzer is good for is comparing visuals on the same page. If five visuals all hit the same measure and four of them are fast and one is slow, the slow one is probably doing something extra. Maybe it's filtering differently, or it has more dimensions, or the visual itself is heavier. You can see this immediately from the trace.
DAX optimisation: where we actually spend time
When the cause is DAX, the work splits into a few patterns we keep seeing:
Variables that aren't variables. Repeatedly recalculating the same expression in a measure because someone forgot VAR exists. Adding VAR/RETURN usually cuts query time noticeably with no other changes.
Iterator functions over the wrong table. SUMX over a fact table with 50 million rows when you should have been summing a pre-aggregated table. The query plan looks fine until you check the row count.
Filter context confusion. Measures that work by accident because of cross-filtering, and break the moment someone changes a slicer. Often the fix is to be explicit about CALCULATE and the filters you want applied.
Bidirectional relationships. They look convenient. They cause query plans to explode. Almost every performance investigation we run finds at least one bidirectional relationship that should be a one-way relationship with a measure pattern instead.
We've written about a few of these in our Power BI consulting work, but the short version is that fast DAX is mostly about making the engine's job easy. Pre-aggregate when you can, use star schemas, avoid iterating over millions of rows, and be explicit about what you're filtering.
When the answer is architecture, not optimisation
There's a point where you can't fix the report. The model is too big, the source data is too remote, or the concurrent query load is too high for the SKU. At that point the conversation has to move from "tune the report" to "change the architecture".
The two options Microsoft suggests are Azure Analysis Services or moving to Premium capacity. We mostly recommend Premium for clients already invested in the Power BI ecosystem because it integrates more cleanly. Azure Analysis Services is a better fit when you've got non-Power BI clients hitting the same tabular model, or when you need the specific deployment control that the Azure service gives you.
If the problem is a Direct Query model talking to a slow source, you sometimes have to admit Direct Query was the wrong choice and switch to Import. Yes, you lose real-time data. No, your users probably didn't actually need real-time data. They thought they did. Most "real-time" requirements turn out to be "refreshed every 15 minutes is fine" once you ask the right questions.
What we tell clients before starting an investigation
A quick checklist that has saved us from chasing ghosts:
Confirm the user isn't on a corporate VPN that's adding latency. Sounds obvious. Has been the answer twice this year.
Confirm the report has been actually published, not just opened in Desktop. Desktop performance is not service performance.
Confirm whether the user is opening the report fresh or refreshing it with new slicer selections. The first load includes warm-up time. Repeated interactions don't. They have different optimisation paths.
Get specific timing data. "It's slow" is not a starting point. "The header KPI cards take 12 seconds and the detail table takes 30" is something we can work with.
The performance work for Australian organisations we do for is usually less about cleverness and more about discipline. The flowchart Microsoft published is the discipline framework. The Performance Analyzer is the measurement tool. The DAX patterns are the fixes. None of it is rocket science, but doing it in the right order saves weeks of wasted effort.
Reference: Microsoft Power BI - Troubleshoot report performance