Data & AI · 14 min
How to Optimize Microsoft Fabric Workloads and Prevent Capacity Throttling
A practical method to find the Fabric workload consuming your capacity, reduce its CU footprint, and decide when optimization, isolation, or scaling is the right fix.
Amrutha Satishkumar
September 19, 2026
Your capacity is throttling. Do not start with the SKU.
A report takes twenty seconds to open. A pipeline that normally finishes before breakfast is still running. Someone sees the capacity above 100% and proposes the obvious fix: move from F64 to F128.
That might be the right decision. It should not be the first one.
Microsoft Fabric brings data engineering, warehousing, real-time analytics, data science, and Power BI onto shared capacity. That is one of its strengths. It also means one inefficient item can consume compute that another workload needs. A poorly shaped warehouse query, an oversized Spark session, an hourly refresh of data that changes once a day, or a report page with too many expensive visuals can all surface as the same complaint: “Fabric is slow.”
The complaint does not tell you the cause.
The useful operating model is:
Confirm the capacity is throttling. Isolate the operation creating pressure. Optimize that workload. Scale only when the remaining demand is legitimate.
This distinction matters because a larger SKU gives inefficient work more room to run. It does not make the work efficient.
First, separate slow performance from throttling
Slow performance and capacity throttling can look similar to a user, but they are different problems.
A report visual can be slow because its DAX is expensive. A warehouse query can be slow because it scans far more data than it needs. A Spark job can wait because it requested more executors than are available. Network latency, gateway pressure, cold cache, locks, and source-system performance can also add delay.
Throttling is more specific. It happens when billable operations consume more Capacity Unit seconds than the capacity can supply, including the future capacity Fabric uses to absorb smoothed usage. When that budget is exhausted, Fabric progressively delays or rejects new work.
This leads to the first rule:
Do not diagnose throttling from a slow screen or a utilization spike. Confirm it in the Capacity Metrics app.
Microsoft explicitly notes that utilization above 100% does not immediately mean throttling. Fabric allows bursting, smooths usage, and provides limited overage protection before user operations are affected.
Use the Throttling view and System events on the Compute page to confirm whether the capacity entered interactive delay, interactive rejection, or background rejection. Rejected requests can also surface errors such as CapacityLimitExceeded.
If the app shows no throttling during the incident, investigate the item itself. Buying capacity to fix a bad query is an expensive way to avoid reading its execution plan.
What Fabric is protecting you from
Fabric does not force every operation to fit inside the CU budget of the current second. It uses two mechanisms to absorb variability.
Bursting lets an operation temporarily use more compute than the provisioned SKU provides so it can finish quickly.
Smoothing spreads the CU accounting for that operation across future 30-second timepoints. Interactive operations are typically smoothed over five to 64 minutes, depending on consumption. Background operations are typically smoothed over 24 hours.
Smoothing is not a performance optimization. It does not make a query cheaper or slow a job down to fit the capacity. It changes how consumed compute is applied against the capacity limits.
When smoothed usage continues to accumulate faster than idle capacity can pay it down, Fabric moves through progressive protection stages:
| Future capacity consumed | Protection stage | User impact |
|---|---|---|
| Up to 10 minutes | Overage protection | New operations continue without throttling |
| More than 10 minutes, up to 60 minutes | Interactive delay | New interactive operations receive a 20-second submission delay |
| More than 60 minutes, up to 24 hours | Interactive rejection | New interactive operations are rejected |
| More than 24 hours | Background rejection | New interactive and background operations are rejected |
Operations already running are allowed to complete. The capacity recovers when unused CUs burn down the accumulated carryforward.
That delayed accounting explains a common mystery. The item users see failing at 10:00 AM might not be the item that created the pressure at 10:00 AM. A large background operation completed earlier can still be consuming future capacity through smoothing.
Diagnose from the capacity down, not from the complaint up
When a capacity incident occurs, use the same investigation path every time.
1. Pin down the affected window
Record the time, capacity, workspace, reported symptom, and whether the failure affected interactive work, background work, or both. Do not begin with a full month of data. Start with the narrowest window that contains the incident.
The Capacity Metrics app retains a recent compute view and displays hourly usage in the multimetric ribbon. Select the affected day and hour. When filters are applied, the utilization and throttling visuals can show 30-second timepoints rather than only periodic peaks.
2. Confirm the protection stage
Open the Throttling tab and check which threshold crossed 100%:
- Interactive delay means the capacity consumed more than 10 minutes of future capacity.
- Interactive rejection means it consumed more than 60 minutes.
- Background rejection means it consumed more than 24 hours.
Then review Overage (Carryforward). The add, burndown, and cumulative values tell you whether the capacity experienced a short surge that quickly recovered or sustained demand that kept adding debt.
Minutes to burndown is especially useful. It estimates how long recovery would take if no new operations entered the capacity.
3. Find the items that consumed the CUs
In the matrix by item and operation, sort by CU (s) for the selected window. Expand the highest consumers to see the operation type. Duration alone is not enough. A long-running operation can use modest compute, while a short burst can consume many CUs.
Add the optional columns that help explain the incident:
- Rejected count
- Failed count
- Successful count
- In-progress count
- Overloaded minutes
- Item size
- Performance delta
Hovering over matrix values exposes the operation-level breakdown. Capture the workspace, item, operation, user or service principal, CU seconds, operation count, and time.
4. Classify the shape of the problem
Most incidents fall into one of four patterns:
| Pattern | What the evidence looks like | Likely response |
|---|---|---|
| One expensive operation | A single run dominates CU seconds | Optimize code, query, model, or data layout |
| Excessive frequency | A modest operation runs far more often than its data changes | Reduce refresh or execution frequency |
| High concurrency | Many acceptable operations overlap | Control concurrency, isolate workloads, or scale |
| Sustained business demand | Optimized work remains consistently high | Scale up or scale out |
This classification prevents random tuning. It tells you whether to reduce cost per operation, reduce operation count, change where the work runs, or provide more compute.
Reducing frequency and rescheduling are not the same optimization. Changing an hourly refresh to a daily refresh removes unnecessary executions and lowers total consumption. Moving the same 24 hourly refreshes to a different part of the day does not make them cheaper. It only changes when they compete with other work.
Optimize the workload that actually caused the pressure
Fabric experiences share a capacity, but they do not share one tuning playbook. Apply the fix at the workload boundary where the CUs were consumed.
Warehouse and SQL analytics endpoint
For a Warehouse or SQL analytics endpoint, start with Query Insights. It retains historical query information for completed user queries and exposes views for long-running, frequently executed, and CPU-intensive requests.
This query identifies completed requests with the highest allocated CPU time:
SELECT TOP 100
distributed_statement_id,
query_hash,
allocated_cpu_time_ms,
label,
command
FROM queryinsights.exec_requests_history
ORDER BY allocated_cpu_time_ms DESC;
Then look for the reason those queries are expensive:
- Return only the columns and rows the consumer needs. Avoid
SELECT *on large analytical tables. - Filter early so joins and aggregations process less data.
- Use a star schema where it fits the analytical workload.
- Keep statistics current, especially after substantial loads or updates.
- Match data types on join and filter columns to avoid conversion work.
- Use the smallest appropriate data types and string lengths.
- Batch small inserts, updates, and deletes instead of creating a stream of tiny transactions.
- For Lakehouse tables, run table maintenance when small-file accumulation or poor layout increases scan cost. Maintenance also consumes CUs, so compare its recurring cost with the query savings it creates.
- Consider partitioning for predictable, lower-cardinality filters and clustering for selective filter columns.
Do not judge a warehouse query from its first run alone. Cold cache, statistics creation, and node initialization can make the first execution slower. Query Insights exposes remote, memory, and disk scan information that helps distinguish a cold start from a persistent query problem. Run the same representative query several times, separate the cold execution, and compare the later runs under similar conditions.
The target is not merely a faster query. It is fewer CPU milliseconds, less data scanned, and fewer CU seconds for the same business result.
Spark, notebooks, and lakehouse processing
Spark pressure often comes from the relationship between data layout, code, executor use, and session lifetime.
Start with the Spark monitoring experience and the Tune tab. Look for skewed stages, large shuffles, spills, underused executors, and jobs that reserve more compute than they use.
Common fixes include:
- Filter and project early instead of carrying unused rows and columns through every transformation.
- Avoid unnecessary shuffles and repeated actions over the same data.
- Choose partitioning based on actual data volume and access patterns.
- Compact small Delta files after material changes rather than forcing every reader to pay the metadata cost.
- Use broadcast joins only when the smaller side is genuinely small enough.
- Cache only data that is reused and can fit responsibly in memory.
- Reserve the executors the job requires instead of assuming more parallelism is always better.
- Stop active Spark sessions when they are no longer needed. Idle sessions can continue to accrue capacity utilization until they expire.
If Spark is bursty and regularly competes with reporting or warehouse workloads, optimization might not be the whole answer. Fabric’s on-demand billing for Spark can move Spark jobs off the shared Fabric capacity and onto separately billed serverless resources. That changes the cost and isolation model, so evaluate it against a measured Spark baseline rather than enabling it by instinct.
Data Factory pipelines and Dataflow Gen2
For pipelines, separate orchestration cost from the work performed by the activities they invoke. A pipeline can trigger notebooks, copy operations, stored procedures, and semantic model refreshes. The expensive operation might appear under the destination workload rather than under the pipeline itself.
Look for waste in three places:
- Frequency: Do not refresh hourly when the source changes daily.
- Movement: Incremental loads should move changed data, not repeatedly copy complete history.
- Transformation: Push transformations to the source through query folding when that source can execute them efficiently.
For Dataflow Gen2, merging, sorting, and other expensive Power Query operations become much more costly when folding breaks and the dataflow must retrieve and process a large source locally. Verify folding before treating a transformation as production-ready.
Concurrency controls can protect downstream systems and reduce contention, but remember that simply moving background jobs to different hours does not reduce their total CU consumption. Fabric already smooths many background operations over 24 hours. Schedule changes are useful when they reduce direct runtime contention, source pressure, or overlap with a critical user window. They are not a substitute for removing unnecessary work.
Power BI semantic models and reports
Power BI can create pressure from both directions: background refreshes consume capacity over time, while report queries compete for interactive responsiveness.
For background operations:
- Use incremental refresh for large fact tables when full refresh is unnecessary.
- Preserve query folding so refresh work is pushed to the source where appropriate.
- Remove unused columns and reduce high-cardinality data where the business requirement allows it.
- Avoid refreshing more frequently than the source changes.
- Prevent large numbers of subscriptions or paginated reports from bursting at the same time.
For interactive operations:
- Tune expensive DAX measures rather than hiding their cost behind a larger SKU.
- Use a clear star schema with efficient one-to-many relationships.
- Limit visuals on a report page to those needed for the decision.
- Apply restrictive default filters instead of asking a visual to load an unbounded result and waiting for the user to filter it.
- Avoid table visuals that return very high-cardinality results.
- Test row-level security logic because complex filters can multiply query cost.
Use Performance Analyzer in Power BI Desktop to identify expensive visuals, then correlate the deployed semantic model with the item and operation view in Capacity Metrics. Optimization is strongest when design-time evidence and capacity-level evidence point to the same operation.
Real-Time Intelligence
Real-time workloads need a different lens because continuously running ingestion and low-latency queries are part of the design.
For KQL databases and Eventhouses:
- Restrict query time ranges and project only required columns.
- Use materialized views for repeated aggregations where the maintenance trade-off is justified.
- Review retention and caching policies against the actual query horizon.
- Batch ingestion where latency requirements permit it.
- Avoid repeated wide scans for dashboard queries that can use pre-aggregated results.
Measure query latency, ingestion delay, throughput, and CU consumption before and after each change. A cheaper workload that no longer meets the required freshness target is not optimized.
Real-Time Intelligence also has workload-specific throttling behavior. It does not apply the initial 20-second interactive delay stage because that would undermine the real-time experience. Do not assume every Fabric workload presents throttling in exactly the same way.
Reduce blast radius when optimization is not enough
Some workloads are efficient and still should not share a failure boundary.
An executive reporting estate, a self-service experimentation workspace, and a large overnight engineering platform can have different service expectations. If one workload is allowed to consume the headroom needed by another, the architecture is coupling them operationally even if their data products are separate.
Fabric gives you several options:
- Scale up when optimized demand legitimately exceeds the current SKU.
- Scale out by moving workspaces to another capacity when isolation, administration, or service levels differ. This adds capacity cost and operational ownership, so the service-level benefit must justify it.
- Use on-demand billing for Spark when dynamic Spark demand should not consume the shared capacity.
- Configure surge protection to limit the background compute that can consume a capacity and make interactive throttling less likely.
- Enable capacity overage billing when continuity is worth the additional overage cost and the feature fits your operating model.
Surge protection is a guardrail, not free capacity. When it activates, background jobs can be rejected. Microsoft recommends correctly sizing and isolating critical solutions rather than treating surge protection as a replacement for optimization or capacity design.
Prove that the optimization worked
A workload is not optimized because its code changed or one test completed faster. Compare the same business operation before and after the change.
Track:
| Measure | Why it matters |
|---|---|
| CU seconds per operation | Shows whether the work became cheaper |
| Operation count | Exposes unnecessary frequency and retries |
| Total CU seconds | Shows the net capacity effect |
| Duration | Measures user or batch completion time |
| Data scanned | Reveals pruning, cache, and query-shape improvements |
| Rejected and failed count | Confirms whether capacity pressure still disrupts work |
| Carryforward and minutes to burndown | Shows whether the capacity recovers faster |
| Interactive latency | Confirms that users experience the improvement |
Run the comparison over a representative period. A change that improves one query but shifts expensive work into refresh, maintenance, or another engine is not an end-to-end optimization.
For recurring operations, calculate both cost per run and daily cost:
Daily CU-seconds = CU-seconds per operation × operations per day
Reducing a query from 1,000 to 800 CU seconds saves 20% per run. If it runs ten times more often after the redesign, total consumption still increases substantially. Efficiency and frequency belong in the same calculation.
A practical throttling response worksheet
Use this during the next capacity incident:
Incident window:
Capacity and SKU:
User-visible symptom:
Confirmed throttling stage:
Carryforward and minutes to burndown:
Top workspace:
Top item:
Top operation:
Interactive or background:
CU-seconds:
Operation count:
Rejected count:
Problem shape:
[ ] One expensive operation
[ ] Excessive frequency
[ ] High concurrency
[ ] Sustained business demand
Optimization applied:
Before CU-seconds per operation:
After CU-seconds per operation:
Before daily CU-seconds:
After daily CU-seconds:
Problem shifted to refresh, maintenance, or another engine:
Decision:
[ ] Keep current SKU
[ ] Scale up
[ ] Isolate on another capacity
[ ] Move Spark to on-demand billing
[ ] Add a protective capacity control
This turns a vague performance complaint into a traceable engineering decision.
The goal is not zero utilization
A well-used Fabric capacity should do work. The goal is not to keep every chart comfortably low or eliminate every temporary excursion above 100%.
The goal is to ensure that each operation earns the compute it consumes, critical workloads retain the service level they need, and sustained business demand fits inside a deliberate capacity envelope.
When throttling appears, ask these questions in order:
- Did the capacity actually throttle, or is one item simply slow?
- Which item and operation consumed the CUs?
- Is the problem cost per operation, frequency, concurrency, or real growth?
- Can the workload be made cheaper without reducing the business outcome?
- If not, should the answer be more capacity or better isolation?
That is the difference between reacting to throttling and operating Fabric well.
Once the workloads are efficient and the remaining demand is understood, automation becomes useful. Automating Microsoft Fabric Capacity Scaling covers scheduled and reactive ways to resize or pause an F SKU without turning scaling into the first response to every incident.
Sources
This article is grounded in current Microsoft documentation. Product behavior and preview features can change, so verify the latest guidance before making production capacity decisions.
- Understand capacity throttling and smoothing (Microsoft Learn)
- Capacity Metrics app compute page (Microsoft Learn)
- Evaluate and optimize your Microsoft Fabric capacity (Microsoft Learn)
- Performance guidelines for Fabric Data Warehouse (Microsoft Learn)
- Query Insights in Fabric Data Warehouse (Microsoft Learn)
- On-demand billing for Apache Spark in Microsoft Fabric (Microsoft Learn)
- Optimization guide for Power BI (Microsoft Learn)
Amrutha Satishkumar
Data & AI Solution Engineer at Microsoft