Skip to main content
Power BI

Why Is My Power BI Report Slow After Migrating to Fabric?

Your operations report loaded in two seconds on Import mode. Now it is on Direct Lake and it is slower — which feels like a broken promise, because Direct Lake was sold as Import speed with DirectQuery freshness. A slow Direct Lake report almost never has an exotic cause.

Amit Kumar Singh - Technology Consulting Partner at MyData Insights

Technology Consulting Partner · MyData Insights

14+ years in industrial data · Former Accenture & EY · India, GCC, SEA

19 August 2026 · 13 min read

The bottom line

A Power BI report that got slower after a Fabric migration almost never has an exotic cause. Most common is silent DirectQuery fallback — a Direct Lake on SQL model reverting to DirectQuery because of a SQL view, SQL-based row-level security, or a breached guardrail, with no error to tell you. Then capacity throttling (the query is fast, the user is delayed), cold-cache transcoding after framing, small-file Delta tables with V-Order off by default, and per-SKU guardrail breaches. Work the cheap checks first: Performance Analyzer for fallback, the Capacity Metrics Throttling tab, repeat the visual for cold cache, count files and rows against your SKU. If all clear, it is model or report design.

It loaded in two seconds on Import — and now it does not

Your operations report refreshed at 06:00, the plant managers opened it at 07:00, and nobody complained. You migrated to a Direct Lake semantic model, and now it is slower. That feels like a broken promise, because Direct Lake was sold on performance: Import-mode speed with DirectQuery freshness, no refresh window, no 2 a.m. failures.

Resist the urge to blame Direct Lake for two weeks. A slow Direct Lake report almost never has an exotic cause — it has one of about seven ordinary ones, and they are cheap to check in order.

The diagnostic order — cheap checks first

CheckToolRules out
Is the query falling back to DirectQuery?Performance Analyzer in Power BI DesktopFallback
Is the capacity throttling?Capacity Metrics app, Throttling tabDelay vs slowness
Slow only on the first query after a refresh?Repeat the same visual twiceCold cache
How many Parquet files / row groups per table?Lakehouse table properties / Delta logSmall-file fragmentation
Is V-Order on for the tables the model reads?Table propertiesCompression/transcoding cost
Are you inside the SKU guardrails?Row, file, model-size counts vs the SKU tableGuardrail breach
What did the model inherit from Import?Best Practice Analyzer, relationship viewModel design
How many visuals on the slow page?Count themReport design

Each check either eliminates a cause or gives you the fix. Do not read the query plan until you have ruled out fallback and throttling.

Cause 1: DirectQuery fallback — the report is not on Direct Lake at all

Direct Lake on SQL endpoints fall back to DirectQuery when they cannot read the Delta table directly — most often a non-materialised SQL view, SQL-based row-level security, object-level security, dynamic data masking, or a table over guardrail. Nothing tells you it happened: the report still works, nobody sees an error, it is simply slower, and the team concludes Direct Lake is overrated.

Views and RLS catch migrating teams hardest, because teams carrying a SQL Server or SAP extract habit build a curated view layer — vw_Sales_Fact, vw_Inventory_Position — because that is how they have always presented data to Power BI. Detect it in Power BI Desktop: View → Performance Analyzer → Start recording → Refresh visuals, then expand the slow visual and look for a "Direct query" metric. Fix it by materialising those views into Delta tables (or setting the model's Direct Lake behaviour to DirectLakeOnly in development so fallback surfaces as an error you can find, rather than as silent slowness).

Cause 2: capacity throttling — the report is not slow, it is delayed

This is the most misdiagnosed cause, because the symptom is wrong: the DAX query completes in 400 milliseconds and the user still waits twelve seconds. Fabric smooths interactive operations over 5–64 minutes and background operations over 24 hours, then charges them against future capacity — and once smoothed usage exceeds 10 minutes of future capacity, Fabric delays every interactive job by 20 seconds at submission.

The tell is the shape: a genuine query problem is proportional (heavier visual, slower response), while throttling delays even trivial visuals by a flat amount. In most mid-market estates it is not the report — it is a Spark notebook or a full-reload pipeline on the same capacity, smoothed across 24 hours, eating the headroom the report needs at 08:00. Open the Capacity Metrics app Throttling tab for the hour users complain about; separate engineering from serving onto different capacities.

Causes 3 & 4: cold cache and Delta table health

Direct Lake loads column data from OneLake only when a query first requests that column — transcoding — and on a cold model the engine must merge local Parquet dictionaries into a global VertiPaq dictionary before answering. That is why the CFO at 07:05 waits eleven seconds and everyone at 07:20 waits two: it is the residency state, not randomness. Incremental loads beat overwrites — the Overwrite option erases the Delta log, so Direct Lake cannot use incremental framing and must reload everything; insert-only patterns let dictionaries survive. A warm-up query after the pipeline hides the cost from the first user.

Delta health compounds it: each row group across a table's Parquet files becomes a column segment, and every extra row group is another local dictionary to merge during transcoding — so small files hurt Direct Lake more than a warehouse, where file skipping makes a bad layout survivable. And V-Order is now off by default for new workspaces, a choice that favours ingestion write performance — for Direct Lake serving tables you generally want it on (ALTER TABLE … SET delta.parquet.vorder.enabled = true, then OPTIMIZE … VORDER). Near-real-time ingestion makes this worse; schedule OPTIMIZE on gold tables as a production job.

Cause 5: guardrail breaches for your SKU

Direct Lake enforces per-SKU guardrails on Parquet files, row groups, rows and model size per table.

SKUParquet files / tableRow groups / tableRows / tableMax memory
F2–F81,0001,000300 million3 GB
F161,0001,000300 million5 GB
F321,0001,000300 million10 GB
F64 / P15,0005,0001.5 billion25 GB
F128 / P25,0005,0003 billion50 GB
F256 / P35,0005,0006 billion100 GB

The Parquet-file guardrail is the one that catches mid-market estates, and it connects straight to Delta health: an F16 workspace with a fifteen-minute incremental load and no compaction crosses 1,000 files on a busy fact table long before it approaches 300 million rows — at which point Direct Lake on OneLake falls back to DirectQuery. Compaction (OPTIMIZE) is the fix.

Causes 6 & 7: model and report design you carried over

Three model habits transfer badly from Import. Calculated columns and calculated tables that reference Direct Lake columns are not supported on either flavour. Bi-directional relationships that were tolerable in Import cost more here; Microsoft's guidance is to minimise them, especially as their number grows — replace with CROSSFILTER in measures. And high-cardinality columns increase transcoding time, because dictionary merging is the dominant cold-query cost.

And sometimes it is the report, and it always was. A landing page with a dozen KPI cards, four matrices and six slicers was slow on Import too — Import was simply more forgiving under concurrency. Microsoft's guidance is explicit: limit visuals per page to only what is necessary, and use drillthrough pages and tooltips instead of adding more. The fix is editorial: one page, one decision, the fewest visuals that support it.

Symptom to cause to fix

SymptomLikely causeFirst fix
Uniformly slow, every visual, all users, all dayDirectQuery fallbackSet DirectLakeOnly, find the trigger, materialise views
Slow in blocks matching pipeline schedules; even trivial visuals delayedCapacity throttlingCapacity Metrics → Throttling tab; separate engineering from serving
First user after refresh slow, everyone after fastCold cache / framing evictionWarm-up query post-pipeline; switch overwrite to incremental
Gradually degraded over weeks, no code changeSmall-file accumulationOPTIMIZE … VORDER, schedule compaction
Fast in dev, slow in prod workspaceV-Order disabled on the newer workspaceCheck delta.parquet.vorder.enabled per table
One large fact table slow, others fineGuardrail breach on that tableCount files, row groups, rows against the SKU table
Slicer interactions much slower than card refreshesBi-directional relationshipsReplace with CROSSFILTER in measures
Slow on one page onlyToo many visualsSplit the page; use drillthrough

Where this breaks, and what it does not fix

Some estates genuinely were faster on Import, and Import remains a legitimate choice — if your model is under a few GB, data lands once a night, and nobody needs intraday freshness, Import gives you a fully warm VertiPaq cache with no transcoding, framing eviction or fallback surface. This diagnostic will not fix a bad gold layer: if fact tables are wide, unmodelled and joined at query time, no storage mode saves you.

Capacity Metrics is retrospective, so a complaint at 08:10 may not surface for some minutes. The SQL analytics endpoint's metadata sync adds its own lag — normally under a minute, but the background process halts after 15 minutes of inactivity, and a workspace holding many lakehouses increases latency. Fixing fallback can even make freshness worse, since DirectQuery fallback queries always return the latest data. And none of this addresses trust — a fast report nobody believes is not a win.

What to do first

Answer these five this week, before changing anything:

  • Run Performance Analyzer on the slowest page — does a "Direct query" metric appear?
  • Open the Capacity Metrics Throttling tab for the hour users complain about — is the 10-minute interactive line crossing the delay threshold?
  • Refresh the same visual twice — is the second run dramatically faster?
  • Count Parquet files and rows on your three largest fact tables against the guardrail table for your SKU
  • Check delta.parquet.vorder.enabled on those tables — if the workspace is recent, assume V-Order is off until proven otherwise

If you clear all five and the report is still slow, the problem is model or report design — a rebuild conversation, not a tuning one. Bring the Performance Analyzer output and one Capacity Metrics screenshot to a diagnostic call.

The first two checks resolve most cases: Performance Analyzer for a hidden DirectQuery fallback, and the Capacity Metrics Throttling tab for the hour users complain about. If both are clean and it is still slow, it is design, not tuning. Book a diagnostic with Amit — no slides, no pitch deck, no obligation to proceed. Bring the Performance Analyzer output and one Capacity Metrics screenshot.

Free Assessment

Where does your operation sit on the data maturity curve?

8 questions. 3 minutes. You get a scored breakdown across data infrastructure, analytics readiness, and automation potential — with a specific next step for your industry.

Power BIMicrosoft FabricDirect LakePerformanceMigration

Your Data · Our Technology · Our Automation

Get practical insights every fortnight

Amit writes about Microsoft Fabric, Power BI, AI in operations, and digital transformation for manufacturing and supply chain leaders. Practitioner perspective - no fluff, no vendor spin.

No spam. Unsubscribe any time. Also on Substack.

FAQ

Common questions

Is Direct Lake always faster than Import mode?

No. Import mode keeps a fully warm VertiPaq cache with no transcoding cost, so for small models with nightly loads it can be faster in practice. Direct Lake wins where data is large or needs intraday freshness.

How do I know if my Direct Lake model is falling back to DirectQuery?

Use Performance Analyzer in Power BI Desktop: start recording, refresh visuals, and expand the visual. A "Direct query" metric means fallback occurred — most often triggered by a SQL view or SQL-based row-level security.

Why is my Power BI report slow only first thing in the morning?

Almost certainly cold cache. Direct Lake loads column data from OneLake only when a query first requests it, and framing after an overnight refresh can evict resident column segments — so the first user pays the transcoding cost for everyone.

Does V-Order still apply in Microsoft Fabric?

Yes, but it is now disabled by default for all newly created Fabric workspaces to favour write performance for ingestion. For Direct Lake serving tables you generally want it on.

Can capacity throttling make a report look slow when the query is fast?

Yes, and this is a common misdiagnosis. When smoothed usage exceeds 10 minutes of future capacity, Fabric delays interactive jobs by 20 seconds at submission — so even a 400ms query leaves the user waiting.

Do calculated columns work in Direct Lake semantic models?

No. Calculated columns and calculated tables that reference Direct Lake columns are not supported in either Direct Lake on OneLake or Direct Lake on SQL. Move that logic upstream into the model tables.

Is this the challenge you're facing?

Book a 30-minute call. We'll look at your specific operation and tell you what's achievable - plainly and without slides.