Most slow Power BI reports are slow for three reasons: a data model that is bigger than it needs to be, DAX measures that do more work than necessary, and report pages that send too many queries at once. Fix those in that order and most reports become noticeably faster. Below are 15 practical techniques, grouped by where the problem lives, plus the tools to measure the improvement.
Measure first: find the real bottleneck
Do not guess. Power BI Desktop includes the tools you need to see where time is going.
1. Use Performance Analyzer
Go to View > Performance analyzer, select Start recording, then Refresh visuals. Each visual shows its time split into DAX query (the engine calculating), Visual display (rendering) and Other (waiting in line behind other visuals). A visual with a long DAX query time points to the model or the measure; long visual display time points to the visual itself; long "Other" time usually means too many visuals on the page.
2. Inspect the model with DAX Studio and VertiPaq Analyzer
DAX Studio is a free community tool that connects to your open .pbix. Its VertiPaq Analyzer view lists every table and column by memory size and cardinality (number of unique values). In most models, a few columns use the majority of the memory, and those are your first targets. You can also copy a slow visual's query from Performance Analyzer and run it in DAX Studio or in Desktop's DAX query view to test changes.
Shrink and shape the data model
The VertiPaq engine compresses data by column, so fewer columns and fewer unique values mean a smaller, faster model.
3. Remove columns and rows you do not use
In Power Query, remove columns early with Choose columns. Every unused text column, GUID or comment field costs memory. Filter out history no one analyzes, such as data older than the years your reports cover.
4. Reduce cardinality
High-cardinality columns compress poorly. Split a datetime column into separate date and time columns (or drop the time if you do not need it), round decimals to the precision you actually report, and avoid storing unique transaction IDs unless you need them.
5. Turn off Auto date/time
By default, Power BI creates a hidden date table for every date column. In a large model that adds up. Disable it under File > Options and settings > Options > Data load > Time intelligence (for the current file and globally), and use one proper date table marked as a date table instead.
6. Use a star schema
Separate facts (sales, orders) from dimensions (product, customer, date) and connect them with one-to-many relationships. Star schemas are smaller, faster and simpler to write DAX against than one wide flat table. See Star Schema in Power BI: How to Model Your Data.
7. Avoid unnecessary bidirectional relationships
Bidirectional filtering forces the engine to propagate filters in both directions, which costs time and can create ambiguous paths. Keep relationships single-direction unless you have a specific reason, and handle exceptions in DAX with CROSSFILTER inside a measure.
8. Prefer measures over calculated columns
Calculated columns are computed at refresh and stored in memory for every row. If a value is only needed in aggregate, write a measure instead. If you truly need a column, consider creating it in Power Query or in the source database, where it compresses better.
Write efficient DAX
9. Filter columns, not whole tables
Passing an entire fact table to FILTER inside CALCULATE makes the engine iterate every row. A column filter lets it use the compressed column directly:
-- Slower: iterates the whole Sales table
West Sales Slow =
CALCULATE ( [Total Sales], FILTER ( Sales, Sales[Region] = "West" ) )
-- Faster: filters one column
West Sales =
CALCULATE ( [Total Sales], Sales[Region] = "West" )
-- Same, but respects an existing Region filter instead of replacing it
West Sales Keep =
CALCULATE ( [Total Sales], KEEPFILTERS ( Sales[Region] = "West" ) )
Note that the simple column filter replaces any existing filter on Region, while the FILTER version intersects with it. Use KEEPFILTERS when you want the intersecting behavior. If CALCULATE filter behavior is new to you, start with The CALCULATE Function in DAX, Explained Simply.
10. Store repeated results in variables
Variables are evaluated once and reused, which makes measures faster and easier to read:
Sales Growth % =
VAR CurrentSales = [Total Sales]
VAR PriorSales = [Sales LY]
RETURN
DIVIDE ( CurrentSales - PriorSales, PriorSales )
11. Use DIVIDE and avoid error-handling functions in hot paths
DIVIDE handles division by zero safely and efficiently. Avoid wrapping expressions in IFERROR or ISERROR, which add work for every evaluation; prevent the error condition instead.
Optimize report pages and visuals
12. Reduce the number of visuals per page
Each visual sends at least one query. A page with 25 visuals waits on 25 queries. Combine several cards into one multi-row card or new card visual, move detail to drillthrough pages, and use tooltip pages for secondary information.
13. Be careful with slicers and big tables
A slicer on a high-cardinality column (such as customer name with thousands of values) is expensive to render and hard to use; use a search box or a filter pane filter instead. Avoid table visuals that display tens of thousands of rows; show the top N and let users drill through for detail. Under File > Options > Query reduction you can add Apply buttons to slicers and filters so the page does not re-query after every click.
14. Limit custom visuals
Some third-party visuals from AppSource render slower than built-in ones. If Performance Analyzer shows long visual display times on a custom visual, test whether a native visual can do the job.
Speed up refresh and choose the right storage mode
15. Use query folding, incremental refresh and the right storage mode
These three ideas work together:
- Query folding: when Power Query steps can be translated into the source's language (for example SQL), the database does the heavy lifting. Right-click a step and check whether View Native Query is available. Keep folding-friendly steps (filters, column removal) early. Learn more in Power Query M Language: A Practical Introduction.
- Incremental refresh: instead of reloading years of history every night, refresh only recent partitions. You set it up with
RangeStartandRangeEnddate/time parameters and a refresh policy on the table. It works best with a source that supports query folding. - Storage mode: Import is usually fastest for report users. DirectQuery keeps data in the source and sends queries live, so performance depends on the source. Microsoft Fabric adds Direct Lake, which reads data from OneLake without a traditional import. Pick based on data size, freshness needs and your source's speed.
Quick reference
| Symptom | Likely cause | First fix |
|---|---|---|
| Large .pbix file, slow refresh | Unused or high-cardinality columns | Remove columns, split datetime, disable Auto date/time |
| One visual takes seconds | Expensive measure | Column filters, variables, test in DAX Studio |
| Whole page is slow, many short queries | Too many visuals | Consolidate visuals, use drillthrough |
| Slow only after adding security | Complex RLS filter | Simplify role DAX, filter dimensions |
| Nightly refresh takes hours | Full reload of history | Query folding plus incremental refresh |
If you recently added row-level security, review the patterns in Row-Level Security (RLS) in Power BI, since complex role filters run with every query.
Next steps
Open your slowest report, run Performance Analyzer, and write down the three slowest visuals. Then check model size in DAX Studio and remove the heaviest unnecessary columns. Rewrite one slow measure using column filters and variables, and measure again. Small, measured changes beat a full rebuild, and once the model is lean, every new report built on it starts fast.
Watch: video lessons


Frequently asked questions
Why is my Power BI report so slow?
The most common causes are a model with unnecessary or high-cardinality columns, inefficient DAX measures and too many visuals on one page. Performance Analyzer shows which of these is the main problem.
Is Import mode faster than DirectQuery?
For report users, Import is usually faster because data is stored in Power BI's compressed in-memory engine. DirectQuery performance depends on the speed of the source database.
What is DAX Studio?
DAX Studio is a free community tool for writing, running and analyzing DAX queries. Its VertiPaq Analyzer view shows which tables and columns use the most memory in your model.
Does turning off Auto date/time really help?
In models with many date columns it can reduce model size noticeably, because Power BI otherwise creates a hidden date table for each one. Use a single marked date table instead.
Mark this lesson complete to track your rank progress.