Originally published April 2022; substantially updated July 2026.
This post is a complete replacement for and update to my April 2022 post, Power BI Performance Features. That post focused on several performance features that were new or in preview at the time. Four years later, many of those features have matured, Microsoft Fabric has changed the architecture choices available to us, and Direct Lake has become an important part of the conversation. So rather than keep adding notes to an old feature list, I decided to step back and answer the more useful question: How should you design, diagnose, and improve Power BI performance today?
Here’s the bottom line: Power BI performance is not one feature, one setting, or one capacity size. It is the result of a chain that includes the data source, data preparation, storage mode, semantic model, DAX, report design, security, refresh process, and Fabric capacity. A weakness anywhere in that chain can become the bottleneck, which is why randomly changing DAX or buying more capacity often does not solve the real problem. The best approach is to make the right architectural choices first, measure what is slow, and then fix the layer that is actually causing the delay. For more info, see Optimization guide for Power BI.
Start by choosing the right storage mode
The first major decision is how Power BI will access the data. Import, Direct Lake, and DirectQuery are table storage modes, while composite models and hybrid tables are architectures that combine storage modes in different ways. This distinction matters because people sometimes compare all five as though they are equivalent choices. They are related, but they answer different questions: a storage mode tells Power BI how to query a table, while a composite or hybrid design tells you how those modes are arranged across a model or within a table.
| Choice | How it works | Best fit | Main tradeoff |
|---|---|---|---|
| Import | Copies data into the VertiPaq in-memory engine | Fast, highly interactive reports when data can be refreshed on an acceptable schedule | Data freshness depends on refresh, and the model consumes memory |
| Direct Lake | Reads Delta table data in OneLake and loads needed data into VertiPaq on demand | Large, Fabric-centered analytics solutions that need low data latency without a traditional full import | Requires Fabric capacity, well-maintained Delta tables, and attention to capacity guardrails |
| DirectQuery | Leaves data in the source and sends queries to it at report time | Near-real-time requirements, source-enforced security, or data that cannot reasonably be imported | Every interaction depends on source, network, gateway, and concurrency performance |
| Composite model | Mixes storage modes in one semantic model, or uses DirectQuery tables from different source groups | Models in which different tables or sources need different behaviors | Cross-source relationships and mixed execution paths add design and performance complexity |
| Hybrid table | Splits one table into Import partitions plus one DirectQuery partition | Fast historical analysis combined with the newest data from the source | The recent partition still has DirectQuery constraints and requires supported capacity |
There is no universally best storage mode, and that is not a very satisfying answer until you look at the requirements. Import should usually be your starting point because it offers fast in-memory queries and the broadest modeling flexibility. Direct Lake becomes especially attractive when the curated data already lives in Fabric and is too large or changes too often for a traditional import process. DirectQuery is appropriate when there is a specific reason to query the source at report time, but it should not be selected simply because the source contains a lot of data. For more info, see DirectQuery in Power BI and Direct Lake overview.
Import mode: still the right default for many models
Import mode remains the simplest path to consistently fast report interaction. Data is compressed and stored in the semantic model, and report queries are answered by the VertiPaq engine instead of repeatedly going back to the source. That separation is valuable because a report user can click a slicer without waiting for a database, network connection, or gateway to respond every time. Import also gives model authors the richest set of Power Query and DAX capabilities, which is one reason Microsoft continues to recommend starting with Import unless size, latency, governance, or another specific requirement pushes you elsewhere.
The tradeoff is that imported data is only as current as the latest refresh, and a large model needs memory both when it is queried and when it is refreshed. The answer is not automatically to abandon Import; it is often to import less data, reduce unnecessary columns, use appropriate data types, pre-aggregate where practical, and configure incremental refresh for large fact tables. High-cardinality text columns can consume surprising amounts of memory, while columns that nobody uses still have to be stored, processed, and refreshed, so the simplest optimization may be to remove them. For more info, see Data reduction techniques for Import modeling.
Direct Lake: a major Fabric-era option
Direct Lake is a Power BI table storage mode designed for Delta tables in OneLake. Like Import, it uses the VertiPaq engine to process report queries, but it does not create and maintain a traditional full copy of the source data inside the semantic model. A Direct Lake refresh is primarily a metadata operation called framing, which updates the model’s references to the latest Delta table files. This can reduce the time and resource cost associated with making new data available, especially when the source contains a large amount of curated data in a Fabric lakehouse or warehouse.
Direct Lake is not a universal replacement for Import, and bypassing a traditional full import does not make every model automatically fast. Its performance depends on the layout and health of the underlying Delta tables, including file counts, row groups, and table maintenance, as well as model design and available capacity. For new models, Direct Lake on OneLake is the recommended Direct Lake option; unlike Direct Lake on a SQL endpoint, it does not fall back to DirectQuery when a request cannot be served directly from Delta tables. You should still build a proof of concept with realistic data volumes and concurrency rather than assuming the architecture will behave perfectly on the first try. For more info, see Direct Lake overview and Cross-workload table maintenance and optimization.
Direct Lake also shifts more of the data-preparation work to the layer before the semantic model. Instead of creating every transformation inside Power BI, you would typically build cleaned dimension tables, reusable business logic, and summarized fact tables in a Fabric lakehouse or warehouse, where they can be shared by multiple semantic models and other workloads. This is generally a good architectural approach, but it requires the data engineering team and the semantic model developers to work closely together. Even a well-designed semantic model cannot fully overcome poorly organized Delta tables, excessive numbers of small files, or inefficient table structures underneath it. For more info, see Develop Direct Lake semantic models.
DirectQuery: use it for a reason
DirectQuery keeps data in the source and sends queries to that source when users interact with a report. It is useful when data must remain at the source, when source-enforced security is required, when the data changes more quickly than an Import model can reasonably be refreshed, or when the dataset is so large that importing the required level of detail is not practical. By “not practical,” I mean that the data may be too large for the available semantic model or capacity limits, may require too much memory, or may take too long to load and refresh within the available refresh window. In those situations, DirectQuery may be the best option because Power BI can query only the necessary rows from the source instead of copying the entire detailed dataset into the semantic model. The important phrase, however, is “when required.” DirectQuery is not simply Import without a refresh; it changes the performance contract because every visual can depend on the source system, network latency, gateway overhead, and the workload created by every other user. It also depends heavily on query folding, which is the process of translating Power Query transformations into queries that the source system can execute. When query folding works well, filtering, joining, and other processing happen at the source; when it does not, Power BI may need to retrieve more data or perform more work itself, which can significantly reduce performance.
Before choosing a fully DirectQuery model, consider whether incremental refresh, a hybrid table, Direct Lake, or aggregations can meet the requirement with less runtime dependency on the source. If DirectQuery is the right choice, begin by testing representative source queries under realistic concurrency, not just by opening one report when nobody else is using the system. Make sure transformations fold, filter data as early as possible, optimize joins and common predicates, and return only the columns and rows that the report needs. A slow source query does not become fast because Power BI generated it, and increasing the number of simultaneous queries can sometimes make the source slower rather than faster. For more info, see DirectQuery model guidance in Power BI Desktop and Understanding query evaluation and query folding in Power Query.
Report design matters even more with DirectQuery because user actions create source activity. A page with many visuals, several slicers, cross-highlighting, and expensive totals can send a substantial collection of queries from one click. Use query-reduction options, Apply buttons for slicers and filters, and fewer interactions when they improve the experience. There is no magic number of visuals that is always safe, because a simple card and a detailed matrix do very different amounts of work, but every visual should earn its place on the page. For more info, see Optimize ribbon in Power BI Desktop.
Composite models and hybrid tables are not the same thing
A composite model is a semantic model that contains tables using different storage modes, or DirectQuery tables that belong to different source groups. For example, a model might use Import for small dimension tables and DirectQuery for a very large fact table, or combine Direct Lake tables with an imported planning table. Composite models provide flexibility at the table level, but they also introduce more execution paths, relationship considerations, and opportunities for queries to cross storage modes or data sources. In a model that combines Import and DirectQuery, a shared dimension table can be configured with Dual storage mode, which allows Power BI to treat the table as either Import or DirectQuery depending on the query. This can improve performance by letting Power BI answer queries from the in-memory copy when possible, while still allowing the dimension to participate correctly in queries that must be sent to the DirectQuery source. Dual mode should be used deliberately for shared dimension tables, rather than applied to every table by default.
A hybrid table is much more specific. It is one table with one or more Import partitions and a single DirectQuery partition, usually created by configuring incremental refresh and enabling the option to get the latest data in real time. Historical rows are answered from fast in-memory partitions, while the newest time window is queried from the source. A semantic model containing a hybrid table is therefore composite, but most composite models do not contain a hybrid table. You may hear the phrase “hybrid model” in conversation, but the official Power BI feature is a hybrid table, and keeping that terminology straight makes architecture discussions much easier.
| Question | Composite model | Hybrid table |
|---|---|---|
| What does it describe? | The arrangement of tables across a semantic model | The partition design of one table |
| How are modes combined? | Different tables use different modes, or DirectQuery tables use different source groups | One table has Import history and one DirectQuery partition for recent data |
| Typical goal | Combine sources or give different tables different performance and freshness behaviors | Combine fast historical analysis with the latest source data |
| Important caution | Cross-source relationships and mixed modes can increase query complexity | Queries touching the recent partition still depend on DirectQuery performance |
The easiest way to remember the difference is this: composite is model-level, while hybrid is table-level. Use a composite model when different tables genuinely require different access patterns or data sources. Use a hybrid table when one time-partitioned fact table needs imported history and near-real-time recent data. In either case, test queries that cross the storage boundaries, because those are often the queries that reveal design problems. For more info, see Use composite models in Power BI and Semantic model modes in the Power BI service.
Incremental refresh: refresh what changed, not everything
Incremental refresh partitions a table so Power BI can refresh a recent range instead of repeatedly reloading the entire history. This is especially valuable for large fact tables in which older rows rarely change, because the refresh process can focus on the newest or recently updated partitions. It reduces refresh time, source load, and capacity consumption, while also making it practical for an Import semantic model to retain more history. With supported capacity, the policy can also include a DirectQuery partition for the latest data, which is how the common hybrid-table design is created.
Incremental refresh does not rescue a poorly designed ingestion query. The date filters used by the policy must reach the source efficiently, and the Power Query transformations should fold whenever the connector and source support folding. Check the generated native query, filter early, avoid unnecessary columns, and confirm that the source can isolate the requested date range without scanning everything. Also plan the initial historical load carefully, because the first refresh still has to populate the partitions before subsequent refreshes receive the full benefit. For more info, see Configure incremental refresh and real-time data for Power BI semantic models and Best practices when working with Power Query.
Aggregations: answer common questions with less work
User-defined aggregations can dramatically improve a DirectQuery model when users repeatedly ask questions at a summarized grain. Instead of sending every query to a very detailed fact table, Power BI can answer eligible queries from a smaller imported aggregation table. If you worked with aggregations in SSAS Multidimensional, the basic idea will feel familiar: the engine tries to answer common summarized queries from a pre-aggregated structure instead of repeatedly scanning detailed data. The implementation is different, however, because Power BI typically uses a separate aggregation table that is mapped to the detailed table through aggregation properties, relationships, and measures. This works best when you understand the common query patterns and create aggregation tables that reflect how people actually use the reports.
Automatic aggregations take a more managed approach by using query history and machine learning to create and maintain in-memory aggregations for eligible DirectQuery semantic models on supported capacity. They can reduce the specialized modeling effort required to identify useful aggregates, but they are not a reason to ignore the source or the model. You still need representative usage history, enough capacity headroom, and a DirectQuery design that behaves correctly when a query cannot hit an aggregation. For more info, see User-defined aggregations and Automatic aggregations overview.
Query caching is a different feature and should not be confused with aggregation tables. For eligible Import semantic models on supported dedicated capacity, it can cache results for the initial report page a user opens, with results kept in the appropriate user and security context. It does not cache every interaction a user performs after the page opens, and it does not turn a slow model into a fast one. Think of it as a useful optimization for repeated landing-page queries, not as a substitute for good modeling or DAX. For more info, see Query caching in Power BI Premium or Power BI Embedded.
Build a semantic model that can be fast
A star schema remains the best starting point for most Power BI semantic models. Dimension tables describe the things you filter and group by, while fact tables contain the events or measurements you summarize. This structure gives users a model that is easier to understand and gives the engine clear, efficient relationship paths. A complicated web of tables may feel flexible while you are building it, but that flexibility often becomes ambiguity, slower queries, and DAX that has to work around the model instead of working with it.
Model size matters because every unnecessary byte has a cost somewhere: refresh, memory, eviction, paging, or query scanning. Remove columns and rows that have no reporting purpose, use numeric keys where practical, choose appropriate data types, avoid storing excessive precision, and pay special attention to high-cardinality text columns. Disable automatic date/time when an explicit date dimension is the better enterprise design, and avoid calculated columns that materialize values you could create upstream or calculate efficiently as measures. None of these choices is glamorous, but performance work is often a collection of sensible decisions rather than one dramatic setting.
Relationships deserve the same discipline. Prefer clear one-to-many relationships from dimensions to facts, and minimize bidirectional filtering because it can add processing and create confusing filter behavior. Many-to-many and bridge-table patterns are sometimes necessary, but they should represent a real business relationship rather than repair an unclear model after the fact. Row-level security also adds filters to queries, so design it around efficient dimensions and relationships, then measure performance both with and without the intended role applied. For more info, see Understand star schema and the importance for Power BI, Bi-directional relationship guidance, and Row-level security guidance.
Tune DAX after you identify the slow query
It is tempting to start performance tuning by rewriting the most complicated-looking measure. Sometimes that is the right measure, but sometimes the delay is visual rendering, a source query, a relationship path, or another visual that is blocking the page. Start with Performance Analyzer, find the slow visual, and capture the DAX query it is actually running. Then use DAX query view to test changes in the same filter and grouping context instead of guessing from the measure definition alone.
Once you have identified the DAX bottleneck, look for repeated expressions, unnecessary iteration over large tables, expensive context transitions, filters operating at the wrong grain, and calculations that could be simplified by a better model. Variables can improve readability and avoid reevaluating the same expression, while Boolean filter arguments to CALCULATE can be more efficient than wrapping an entire table in FILTER when the requirement allows it. FILTER is not “bad,” and iterators are not “bad”; they are tools that become expensive when they evaluate more rows or more complex logic than the result requires. For more info, see Use variables to improve your DAX formulas and Avoid using FILTER as a filter argument.
Design report pages with a performance budget
Every visual has a cost. It can issue one or more queries, wait behind other work, render data in the browser, and trigger additional queries when the user changes a slicer or cross-highlights another visual. A page with fewer purposeful visuals is usually easier to understand and often faster than a page trying to answer every possible question at once. Detailed tables and matrices deserve special attention because they can request large result sets, expensive subtotals, and distinct counts that users may not need on the opening page.
Use drillthrough, tooltips, bookmarks, and navigation to reveal detail when it is needed instead of loading everything immediately. For DirectQuery reports, use query-reduction features and Apply buttons so a user can make several selections before Power BI sends new queries. Review visual interactions and disable those that do not add business value, especially when one click causes every visual on the page to recalculate. Then test the report as a user would use it, including common slicer paths, mobile layouts if applicable, row-level security, and the actual capacity where it will run. For more info, see Optimize ribbon in Power BI Desktop.
Large semantic models and high concurrency solve different problems
The large semantic model storage format allows semantic models on supported Fabric capacities to grow beyond the default size limit of 1 GB. This limit refers to the size of the compressed semantic model stored in the Power BI service, not the original amount of data in the source system. With the large storage format enabled, the model can grow up to the limit supported by the Fabric capacity or a lower limit configured by the capacity administrator. For example, a 5-GB Import model would exceed the default 1-GB limit, but it could be supported on an appropriately sized Fabric capacity with the large semantic model storage format enabled. The format also supports XMLA-based write operations and provides more flexibility for managing large models in the service. However, making a larger Import model possible does not make it free: the model still requires memory, refresh processing, sensible partitioning, and enough capacity headroom. Incremental refresh becomes especially important because it allows Power BI to process only the partitions that have changed instead of repeatedly processing the entire model.
Semantic model scale-out addresses a different challenge: many concurrent users querying the same semantic model. It can distribute report queries across one or more read-only replicas while the primary read-write replica handles refreshes and other write operations. For example, users can continue querying a read-only replica while the primary replica processes a refresh, reducing the effect of that refresh on interactive report performance. Scale-out can increase query throughput and help support a larger number of simultaneous users, but it does not make an individual inefficient DAX query run faster. That distinction is important because model size, single-query performance, refresh pressure, and concurrent-user demand are separate problems that may require different solutions. For more info, see Large semantic models in Power BI Premium and Power BI semantic model scale-out.
Diagnose the bottleneck before changing the architecture
Performance Analyzer should be one of the first tools you open when a report feels slow. It records how long each visual takes and separates the time into categories such as the DAX query, DirectQuery activity, visual display, and other processing. That breakdown tells you whether to investigate the measure and model, the underlying source, the visual itself, or contention from other work. You can copy the query or run it in DAX query view, which gives you a repeatable way to inspect results, change measure definitions, and compare behavior.
The Optimize ribbon is useful while building a report because you can pause visual queries instead of waiting for every visual to refresh after each model or formatting change. This is especially helpful with DirectQuery models, where report development itself can generate a surprising amount of source activity. It also exposes optimization presets and query-reduction options, helping you design the interaction pattern rather than accepting the default behavior for every page. For more info, see Use Performance Analyzer to examine report performance, Work with DAX query view, and Optimize ribbon in Power BI Desktop.
When performance is good in Power BI Desktop but inconsistent in the service, examine the Fabric capacity rather than assuming the report changed on the way up. The Fabric Capacity Metrics app shows capacity-unit consumption, utilization over time, throttling, rejected operations, and the items or operations contributing to load. Look for overlap between refreshes, data engineering workloads, and peak report usage, because a well-designed model can still struggle when the capacity has no room left to serve it. Scaling capacity may be the correct decision after you understand the evidence, but scaling first can simply make an inefficient design more expensive. For more info, see What is the Microsoft Fabric Capacity Metrics app? and Evaluate and optimize your Microsoft Fabric capacity.
A practical Power BI performance workflow
When a report is slow, I would work through the problem in the following order. This sequence moves from evidence to architecture instead of starting with the most expensive or disruptive change. You may find the issue in the first few steps, which is much better than rebuilding the model and discovering that one visual was the real culprit. It also gives you a record of what you measured and why you changed something, which will help when another report develops similar symptoms later.
- Reproduce the slow experience using realistic filters, security, data volume, and capacity conditions.
- Use Performance Analyzer to identify the visual and determine whether the delay is DAX, DirectQuery, rendering, or waiting on other work.
- Test the captured query in DAX query view and compare changes rather than relying on impressions.
- Review the semantic model: star schema, relationships, cardinality, unnecessary columns, data types, calculated columns, and row-level security.
- Review the storage mode and confirm that Import, Direct Lake, DirectQuery, composite, or hybrid architecture matches the actual freshness, scale, and governance requirements.
- For source-dependent queries, verify query folding and inspect the generated source query, source execution plan, indexing or table layout, and concurrency behavior.
- Reduce unnecessary report work by simplifying visuals, interactions, detailed results, and slicer behavior.
- Review refresh schedules, incremental-refresh policies, and overlap with peak interactive usage.
- Use the Fabric Capacity Metrics app to check capacity pressure, throttling, and competition from other workloads.
- Scale capacity only after the measurements show that efficient workloads still need more resources.
The order is not a law, but the principle is important: measure before you redesign, and redesign before you simply spend more. Performance problems often cross team boundaries, so involve the report author, semantic model owner, data engineer, source-system owner, and capacity administrator when the evidence points to their layer. The goal is not to make one benchmark look good in isolation; it is to create a reliable experience for real users under real workload conditions. For more info, see Optimization guide for Power BI.
Final thoughts
Power BI now gives us more ways to balance speed, scale, freshness, governance, and cost than it did when I wrote the original post in 2022. Import remains an excellent default, Direct Lake is a major option for Fabric-centered solutions, DirectQuery still has important use cases, and composite and hybrid designs let you mix behaviors when the requirements truly call for it. Incremental refresh, aggregations, query caching, large-model support, and scale-out can all help, but each one solves a particular kind of problem. The hard part is not finding a performance feature; it is matching the feature to the bottleneck.
Here’s the advice I would leave you with: keep the model simple, choose storage modes deliberately, prepare data at the right layer, and measure the actual user experience. Do not assume that the newest architecture is automatically the fastest, or that a larger capacity can repair every design problem. Power BI performance is usually won through a series of clear decisions made from the source all the way to the visual. That may not sound as exciting as one performance setting, but it is much more likely to work.
More info:
Power BI DirectQuery Mode: A Better Choice Than You Might Think
The post Power BI Performance in 2026: A Practical Guide to Faster Semantic Models and Reports first appeared on James Serra's Blog.