Optimize Performance: Make Slow Reports Fast
A slow dashboard frustrates everyone — here is how to find what is slow with Performance Analyzer and the handful of fixes that make the biggest difference.
What you will learn
- Measure what is slow with Performance Analyzer
- Apply the high-impact model fixes (granularity, columns, types)
- Recognise the DAX and visual habits that cause slowness
Why speed matters
A report that takes ten seconds to react to a click feels broken, and people stop using it. Performance is a real, graded skill: a job-ready analyst can take a sluggish report and make it snappy. The good news is that most slowness comes from a few common causes, and Power BI gives you a built-in tool to find them.
Measure first: the Performance Analyzer
Never guess what is slow — measure it. The Performance Analyzer records exactly how many milliseconds each visual takes to draw, so you fix the real culprit instead of the one you assume. To use it:
- On the View ribbon, tick Performance analyzer to open its pane.
- Click Start recording.
- Click Refresh visuals (or interact with the page) so every visual re-runs.
- Read the timings: each visual lists its DAX query, visual display and other time in milliseconds.
Performance analyzer (sorted slowest first)
Table: Sales detail DAX query 4,200 ms <- the slow one
Matrix: Region x Product DAX query 180 ms
Card: Total Sales DAX query 40 ms
Slicer: Region DAX query 25 msNote: Output: The detail Table takes 4,200 ms while everything else is under 200 ms — so the table is the problem, not the model as a whole. Now you know precisely where to spend effort. Click the slow visual’s “Copy query” to paste its DAX elsewhere for deeper analysis. The rule is simple: measure, fix the slowest thing, then measure again.
The biggest win: a smaller, leaner model
Power BI compresses your data in memory; the smaller and simpler the model, the faster everything runs. These model fixes give the largest speed-ups for the least effort:
| Fix | Why it speeds things up |
|---|---|
| Remove unused columns | Every column costs memory even if no visual uses it — drop them in Power Query |
| Lower the granularity | Summarise to the level you actually report on (e.g. daily, not per-second) — far fewer rows |
| Right data types | Whole numbers compress better than text or decimals; fix types in Power Query |
| Avoid huge text/ID columns | High-uniqueness columns (long IDs, free text) compress poorly — remove or split them |
| Star schema | The fact-and-dimension shape (earlier lesson) is what the engine is optimised for |
A worked example: a sales table logged every second (50 million rows) was the reason a report crawled. The team only ever reported by day, so they summarised to one row per day in Power Query — 50 million rows became about 18,000. The model shrank dramatically and every visual went from seconds to instant, with no loss of any number they actually showed.
DAX and visual habits that cost time
Once the model is lean, two more areas commonly cause lag. A few habits help:
- Prefer measures over calculated columns for aggregation — measures are computed on the fly and do not bloat the stored model.
- Use
DIVIDEinstead of/and avoid wrapping huge tables in complex iterators when a simple aggregate will do. - Use variables (
VAR) to compute something once and reuse it, instead of repeating the same expensive sub-expression. - Fewer visuals per page — every visual fires its own query, so 25 visuals means 25 queries on each click. Split into more pages.
- Turn off “Auto date/time” (File → Options) and use your own Date table — the automatic one secretly builds a hidden calendar for every date column.
-- Slower: repeats SUM(Sales[Amount]) twice
Margin % = DIVIDE( SUM(Sales[Amount]) - SUM(Sales[Cost]), SUM(Sales[Amount]) )
-- Faster: compute each sum once with VAR, then reuse
Margin % =
VAR Rev = SUM(Sales[Amount])
VAR Cost = SUM(Sales[Cost])
RETURN DIVIDE(Rev - Cost, Rev)Note: Output: Both measures return the same margin percentage, but the second version calculates Rev and Cost a single time and reuses them, rather than re-running each SUM. On a large model this is faster and, just as importantly, easier to read and fix. Storing a value in a VAR once is a habit worth forming for every non-trivial measure.
Tip: Work in this order: measure with Performance Analyzer → shrink the model (remove columns, lower granularity, fix types) → tidy DAX (measures, VAR, DIVIDE) → reduce visuals per page → measure again. The model fixes almost always give the biggest jump.
Watch out: Do not optimise blindly. Always run Performance Analyzer first — if the slow visual is a giant detail table, no DAX tweak elsewhere will help. And lowering granularity is only safe when you never need the finer detail; summarise to the lowest level your reports actually use, not lower.
Q. Your report is slow. What is the correct first step before changing anything?
✍️ Practice
- Open Performance Analyzer, record a refresh, and identify your slowest visual by its DAX query time.
- Remove two unused columns in Power Query and re-record to see the effect on size and speed.
🏠 Homework
- Take any report, run Performance Analyzer, write down the slowest visual and its time, apply one model fix (remove columns or lower granularity), and report the before/after timing.