Power BI

Power BI Performance: 15 Ways to Make Reports Faster

Speed up slow Power BI reports with 15 fixes: Performance Analyzer, smaller models, efficient DAX, fewer visuals, query folding and incremental refresh.

By DashCore Hub Editorial TeamUpdated 8 min read

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.

Tip: Use integer surrogate keys for relationships instead of long text keys like "STORE-0042-FL". Integers compress better and make joins between tables cheaper.

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.

AI shortcut: Paste a slow measure into ChatGPT or Claude with context: "This DAX measure takes 4 seconds in Performance Analyzer. Sales has 20 million rows and a star schema with Product, Store and Date dimensions. Suggest a faster version, explain why it is faster, and point out any change in results." Then test the suggestion in DAX query view and compare numbers before replacing the original.

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 RangeStart and RangeEnd date/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

SymptomLikely causeFirst fix
Large .pbix file, slow refreshUnused or high-cardinality columnsRemove columns, split datetime, disable Auto date/time
One visual takes secondsExpensive measureColumn filters, variables, test in DAX Studio
Whole page is slow, many short queriesToo many visualsConsolidate visuals, use drillthrough
Slow only after adding securityComplex RLS filterSimplify role DAX, filter dimensions
Nightly refresh takes hoursFull reload of historyQuery 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

My Power BI report is slow: what should I do?by SQLBits · Watch on YouTube ↗
Cómo mejorar el rendimiento de los informes en Power BIby Dapen Centro Estudios · Watch on YouTube ↗Video in Spanish.

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.

Learning with the Academy?
Mark this lesson complete to track your rank progress.
Take the quiz