Slow Power BI is almost never a visual problem. It is the model underneath - too many columns, the wrong table shape, calculations running at view time instead of load time. Removing visuals treats the symptom. Fixing the model is what makes a report open in two seconds instead of forty.
This is the most common thing our Power BI team is called in for, and the diagnosis is nearly always the same. Somebody has built a report that works, it has got slower over a year, and the obvious response - fewer visuals, fewer pages, a bigger capacity - has not helped much.
How to tell where the time is actually going
Before changing anything, find out what is slow. Guessing wastes days.
Performance Analyzer, in the View ribbon. Start recording, refresh the page, and it breaks every visual into DAX query time, visual display time, and other. That split tells you almost everything:
- DAX query dominates - the model or the measure. This is the usual answer
- Visual display dominates - the visual is rendering too many data points. A table with 50,000 rows, a scatter plot with no aggregation
- Everything is slow, evenly - likely DirectQuery, or a capacity under load
If DAX query time is the bulk, and it usually is, the rest of this post applies.
The flat wide table
The single most common cause. Someone joins everything into one big table in Power Query because it is easier to reason about, and Power BI is then asked to do something it is not built for.
Power BI's engine is columnar and compresses each column separately. It is fastest with a star schema - a narrow fact table of numbers and keys, surrounded by small dimension tables holding descriptions. Fewer, smaller columns compress better, and relationships let the engine skip data it does not need.
A flat table breaks that. Every row repeats the customer name, the product description, the region, the salesperson. Repeated text compresses poorly, the table is enormous in memory, and every query scans more than it should.
Restructuring into a star schema is the highest-value change available in most slow reports, and it is invisible to the people using it - same numbers, same visuals, faster.
Columns cost more than rows
This surprises nearly everyone.
Ten million rows with eight columns is comfortable. One million rows with two hundred columns can be a problem. The engine stores per column, so column count and column cardinality - how many distinct values it holds - drive memory more than row count does.
The worst offenders are usually accidental:
- Datetime columns with seconds. A timestamp to the second has millions of distinct values. Split into date and time, or round to the minute, and the column collapses
- Free-text notes and descriptions. Almost never used in a visual and expensive to hold
- GUIDs and long keys. Necessary for relationships, wasteful everywhere else
- Columns nobody has ever used. The whole source table got imported because it was easier than picking
Removing unused columns is the cheapest performance work there is. It takes an afternoon and often halves the model.
Calculations in the wrong place
The same calculation can happen in three places, and the cost differs by orders of magnitude.
Upstream, in SQL or dbt. Cheapest. Computed once during the nightly load, stored as a plain column.
In Power Query, as a calculated column. Middle. Computed at refresh time, stored in the model. Uses memory but not query time.
As a measure at view time. Most expensive per use, and correct for anything that has to respond to what the user filtered.
The mistake is putting static things in the third place. A row-level flag that never changes with the filter context should not be recalculated every time someone clicks. Move it upstream.
This is where a managed data warehouse changes the economics. When data is already cleaned, joined and modeled before Power BI touches it, the report has far less work to do - and every report reading those tables benefits, not just the one you fixed.
Import versus DirectQuery
DirectQuery is slower. Not sometimes - structurally.
Import loads a compressed copy into an in-memory engine built for analytical queries. DirectQuery sends a query to your source database on every interaction, and your report is then only as fast as that database is under whatever else it is doing.
Teams end up on DirectQuery for two reasons. Genuinely needing real-time data, which is rare and legitimate. Or a dataset too large for Import, which usually means the model needs the column work above rather than a different storage mode.
If you need both, composite models let you Import the dimensions and DirectQuery only the large fact table. More complex to maintain, but it keeps most of the speed.
Slow is not the same as failing
Worth separating, because people describe both as "Power BI is broken".
A failing refresh is usually gateway credentials that expired, a source schema that changed underneath the query, a timeout on a query that grew past its window, or an API rate limit. The refresh history names which, and the fix is targeted.
A slow report is the model. Different problem, different work.
If both are happening, fix the refresh first. It is quicker and it stops the calls.
What more capacity does and does not do
Premium or a larger capacity gives a badly modeled report more room to be badly modeled. It genuinely helps - and it is a monthly cost that recurs forever, for a problem that could have been fixed once.
The honest sequence: remove unused columns, restructure to a star schema, move static calculations upstream. Then measure again. If it is still slow with a clean model and real data volume, capacity is the right answer and you will know exactly why you are buying it.
Where to start
Run Performance Analyzer on your slowest page and look at the DAX query column. That single number tells you whether this post applies to you.
Then the cheap wins in order: delete columns nobody uses, split any timestamp into date and time, and check whether your model is one flat table or a star. Those three take a day between them and usually get most of the way.
If the report is slow because it is doing work that should have happened before Power BI opened, that is a modeling problem rather than a reporting one - and it is the same root cause behind two people getting different numbers from the same report.
Frequently asked questions
Why is my Power BI report so slow?
Does the number of visuals on a page affect speed?
Should I use Import or DirectQuery?
Why does my scheduled refresh keep failing?
Will Premium or a bigger capacity fix it?
Published · Updated · Last reviewed




