Power Platform Performance Optimization and Troubleshooting

A slow app frustrates users. A broken flow costs money. A dashboard that takes two minutes to load gets ignored. Power Platform gives you powerful tools, but those tools only stay powerful when you build them correctly. This lesson teaches you how to find what is slowing things down and how to fix it — in Power Apps, Power Automate, Power BI, and Dataverse.

By the end of this lesson, you will know exactly where to look when something is slow or broken, and you will have a checklist of proven techniques to make every solution you build run fast and reliably.

Why Performance Matters in Power Platform

Power Platform solutions run inside Microsoft's cloud, but performance still depends entirely on how you design them. Two apps can connect to the same data source and look identical — but one loads in two seconds while the other takes fifteen. The difference is not luck. It is design choices made during the build.

Performance problems fall into three buckets: too many data requests, requests that are too large, and code that runs at the wrong time. Troubleshooting problems fall into a fourth bucket: something was working and now it is not. Each bucket needs a different approach.

The Four Performance Buckets

┌──────────────────────────────────────────────────────────────┐
│              WHY POWER PLATFORM SOLUTIONS GET SLOW           │
├──────────────────┬───────────────────────────────────────────┤
│  Too many        │ App calls the data source 20 times on     │
│  requests        │ screen load instead of once               │
├──────────────────┼───────────────────────────────────────────┤
│  Requests too    │ App asks for 10,000 records when it only  │
│  large           │ needs 50                                  │
├──────────────────┼───────────────────────────────────────────┤
│  Wrong timing    │ Heavy calculation runs every time a user  │
│                  │ moves a slider, not just on Submit        │
├──────────────────┼───────────────────────────────────────────┤
│  Something broke │ A connector changed, a license expired,   │
│                  │ or a data source was renamed              │
└──────────────────┴───────────────────────────────────────────┘

Power Apps Performance Optimization

Power Apps performance lives or dies by how the app talks to its data sources. Every inefficiency here multiplies as more users open the app simultaneously.

Understanding Delegation

Delegation is the single most important concept in Power Apps performance. When Power Apps delegates a formula to a data source, the data source does the filtering or sorting work on its servers and sends back only the matching records. When Power Apps cannot delegate, it downloads all records to the device and filters them locally.

Imagine a warehouse with one million boxes. You need to find all red boxes. Delegation means the warehouse manager finds them and brings only those to you. Without delegation, you get every single box delivered to your doorstep and you sort through them yourself.

┌────────────────────────────────────────────────────────────────┐
│                    DELEGATION EXPLAINED                        │
│                                                                │
│  Your App          Connector          Data Source              │
│  ─────────         ─────────          ─────────────            │
│                                                                │
│  WITH DELEGATION:                                              │
│  "Give me records  ──────────────►  Filters 1M records         │
│   where City =                      Returns 42 matches  ◄───   │
│   London"                                                      │
│  Result: Fast ✓                                                │
│                                                                │
│  WITHOUT DELEGATION:                                           │
│  "Give me records" ──────────────►  Returns ALL records        │
│  App filters        ◄────────────   (up to 2,000 max)          │
│  2,000 locally                                                 │
│  Result: Slow, incomplete data ✗                               │
└────────────────────────────────────────────────────────────────┘

Which Formulas Delegate

Delegation support depends on both the formula and the connector. For SharePoint and Dataverse, these formulas delegate: Filter, Search, Sort, SortByColumns, and comparison operators like =, <, >. Formulas that never delegate include CountIf, GroupBy, Last, and string operations like Left or Mid on filter columns.

Power Apps shows a yellow warning icon next to formulas that are not delegable. Never ignore that warning in a production app. It means your app is silently showing incomplete data.

Fixing Delegation Problems

When you get a delegation warning, you have three options. First, rewrite the formula using a delegable function — replace CountIf with a Filter combined with CountRows if the connector supports it. Second, move the non-delegable logic to a Power Automate flow, where it runs on a server instead of on the device. Third, create a calculated column in your data source so the filter logic happens at the data layer.

Reducing Screen Load Time

The App.OnStart formula and Screen.OnVisible formula run every time someone opens the app or navigates to that screen. Many builders put large data queries inside these formulas, which creates a noticeable delay before anything appears on screen.

Using Collections to Cache Data

A collection is a temporary table stored in the app's memory. Load your reference data once into a collection during App.OnStart, then use the collection everywhere else in the app. The data source gets called once instead of dozens of times.

// Load once at app start
ClearCollect(colProducts, Products);
ClearCollect(colCategories, Categories);

// Use the collection everywhere else — no data source calls
Gallery1.Items = colProducts

For data that changes frequently, use a combination: load the collection on startup, then refresh it in the background when the user submits a form or presses a Refresh button. Do not refresh the collection every time a screen loads.

Concurrent Loading

By default, Power Apps loads data sequentially — it waits for the first query to finish before starting the second. The Concurrent function runs multiple queries at the same time, which can cut load time significantly when you need several data sets on the same screen.

// Without Concurrent: 3 seconds + 2 seconds + 4 seconds = 9 seconds
ClearCollect(colOrders, Orders);
ClearCollect(colCustomers, Customers);
ClearCollect(colProducts, Products);

// With Concurrent: max(3, 2, 4) = 4 seconds
Concurrent(
    ClearCollect(colOrders, Orders),
    ClearCollect(colCustomers, Customers),
    ClearCollect(colProducts, Products)
);

Lazy Loading for Large Galleries

A gallery that loads 500 items all at once feels sluggish even if the data query is fast, because the app renders all 500 rows immediately. Use the Items property of the gallery with a Filter formula tied to a search box or dropdown so the gallery only renders items the user is actually looking at.

Optimizing Formulas Inside Galleries

Every formula inside a gallery control runs once for each row. A gallery showing 100 rows with a LookUp formula in each row fires 100 separate data queries. This is one of the most common performance mistakes in Power Apps.

The Gallery Formula Trap

┌────────────────────────────────────────────────────────────────┐
│                   GALLERY FORMULA TRAP                         │
│                                                                │
│  Gallery showing 100 Orders                                    │
│                                                                │
│  BAD: LookUp inside each gallery row                           │
│  ─────────────────────────────────────                         │
│  Label.Text = LookUp(Customers, ID=ThisItem.CustomerID, Name)  │
│  → Fires 100 separate queries to Customers table               │
│  → 100 round trips to data source                              │
│  → App freezes while waiting                                   │
│                                                                │
│  GOOD: Join data before the gallery                            │
│  ─────────────────────────────────────                         │
│  AddColumns(Orders, "CustomerName",                            │
│    LookUp(colCustomers, ID=CustomerID, Name))                  │
│  → Runs once when collection loads                             │
│  → Gallery reads from memory, zero data queries                │
└────────────────────────────────────────────────────────────────┘

Use AddColumns with your collection to pre-join data before binding it to the gallery. The LookUp runs once against the in-memory collection, and the gallery displays results instantly.

Controlling App.OnStart Size

App.OnStart is tempting to fill with setup logic, but it blocks the entire app from loading until every line completes. Move heavy queries to the first screen's OnVisible event, and show a loading spinner so users know something is happening. Better yet, use the experimental Named Formulas feature in Power Apps, which evaluates formulas lazily — only when their result is first needed.

Power Automate Performance Optimization

Power Automate flows run in the cloud, which means performance problems show up as long run times and throttling errors rather than UI delays. A well-built flow finishes in seconds. A poorly built flow runs for hours or fails halfway through.

The Flow Run Time Diagram

┌────────────────────────────────────────────────────────────────┐
│               FLOW PERFORMANCE: LOOP PROBLEM                   │
│                                                                │
│  Scenario: Send email to 500 customers                         │
│                                                                │
│  BAD: Apply to Each with HTTP call inside                      │
│  ─────────────────────────────────────────                     │
│  [Get Customers] → [Apply to Each]                             │
│                         ↓                                      │
│                    [Send Email]  ← runs 500 times separately   │
│                                                                │
│  Time: 500 × 1 second = ~8 minutes                             │
│  Risk: Throttling after 300 calls/minute                       │
│                                                                │
│  BETTER: Batch or use bulk action connector                    │
│  ─────────────────────────────────────────                     │
│  [Get Customers] → [Send Bulk Email via connector]             │
│                                                                │
│  Time: ~5 seconds                                              │
│  Risk: None                                                    │
└────────────────────────────────────────────────────────────────┘

Reducing Actions Inside Loops

Every action inside an Apply to Each loop multiplies your total action count by the number of iterations. A flow that loops 1,000 times with 5 actions inside executes 5,000 actions. Power Automate has daily run limits per license, and each action counts against those limits.

Move any action that does not depend on the current loop item outside the loop. Retrieve lookup data before the loop starts and store it in a variable. Only actions that genuinely need per-item data belong inside the loop.

Enabling Concurrency in Apply to Each

By default, Apply to Each processes one item at a time. You can enable concurrency to process multiple items simultaneously. In the loop settings, set Degree of Parallelism to a number between 2 and 50. This reduces total run time dramatically for large data sets.

One caution: if your loop actions write to a shared variable, concurrency causes race conditions. Use Compose to collect results instead, or avoid shared variables inside concurrent loops entirely.

Minimizing Connector Calls

Each connector call in a flow takes time and counts against your connector's throttle limits. SharePoint allows roughly 600 calls per minute per connection. Salesforce allows 100,000 API calls per day. When your flow hits these limits, it fails with a 429 Too Many Requests error.

Getting All Data in One Call

Rather than calling a connector once per item to retrieve details, use a single call with a filter to get all relevant items, then join them in memory using array expressions. The Filter Array action processes data already inside the flow without making additional connector calls.

Using Variables Wisely

Variables in Power Automate are global to the entire flow run. Initializing a variable takes a small but measurable action count. For values you only need inside a single scope, use Compose actions instead. Compose actions are lighter and do not require initialization.

// Instead of:
Initialize Variable → name: tempValue, type: String
Set Variable → tempValue = triggerBody()?['Name']
// Use inside the same scope:
Compose → inputs: triggerBody()?['Name']
// Reference as: outputs('Compose')

Handling Throttling Errors

Throttling happens when your flow makes too many calls to a connector in too short a time. The connector returns a 429 error and tells the flow to retry after a delay. You can make your flow resilient to throttling by enabling the Retry Policy on each action.

In each action's settings, set Retry Policy to Exponential Interval with a count of 4 and an interval of PT5S (5 seconds). This means the flow automatically waits and retries up to 4 times before failing, absorbing short throttle windows without any intervention.

Power BI Performance Optimization

A Power BI report with millions of rows and complex DAX measures can feel instant with the right data model, or unbearable with a poor one. The report itself rarely causes performance problems — the data model almost always does.

Import Mode vs DirectQuery

┌────────────────────────────────────────────────────────────────┐
│              IMPORT MODE vs DIRECTQUERY                        │
│                                                                │
│  IMPORT MODE                    DIRECTQUERY                    │
│  ──────────────────             ─────────────────              │
│  Data copied into               Every visual sends a           │
│  Power BI file                  live query to source           │
│                                                                │
│  ✓ Extremely fast visuals       ✓ Always up-to-date data       │
│  ✓ Complex DAX supported        ✓ No storage size limit        │
│  ✗ Data refreshes needed        ✗ Slow if source is slow      │
│  ✗ Dataset size limit           ✗ Limited DAX support         │
│                                                                │
│  Best for: Most use cases       Best for: Real-time data       │
│  Default choice: Import Mode    requirements only              │
└────────────────────────────────────────────────────────────────┘

Use Import Mode for almost everything. Switch to DirectQuery only when data must be live to the second and your data source is fast. In DirectQuery, every interaction with a visual fires a new query against your database. If that database is slow or poorly indexed, every click in the report will feel unresponsive.

Star Schema Data Modeling

The single biggest performance improvement in Power BI is switching from a flat table to a star schema. A flat table joins everything into one wide sheet with many repeated text values. A star schema separates data into a central facts table (numbers and IDs) and surrounding dimension tables (descriptions and labels).

┌────────────────────────────────────────────────────────────────┐
│                    STAR SCHEMA DIAGRAM                         │
│                                                                │
│   DimDate         DimProduct        DimCustomer                │
│   ──────────      ───────────       ────────────               │
│   DateKey    ┐    ProductKey   ┐    CustomerKey   ┐            │
│   Year       │    ProductName  │    CustomerName  │            │
│   Month      │    Category     │    Region        │            │
│   Quarter    │    Subcategory  │    Segment       │            │
│              │                 │                  │            │
│              │   FactSales     │                  │            │
│              │   ─────────     │                  │            │
│              └─► DateKey       │                  │            │
│                  ProductKey ◄──┘                  │            │
│                  CustomerKey ◄────────────────────┘            │
│                  SalesAmount                                   │
│                  Quantity                                      │
│                  Discount                                      │
└────────────────────────────────────────────────────────────────┘

The facts table contains only numbers and foreign keys — no text. DAX calculations over a star schema run dramatically faster because the engine reads fewer columns per calculation and uses compressed integer lookups instead of slow text comparisons.

Writing Efficient DAX

DAX performance depends on context transitions and filter propagation. Two measures can produce the same number but one takes 100 milliseconds and the other takes 3 seconds, depending on how they are written.

Avoid CALCULATE Inside SUMX Row Context

Placing a CALCULATE inside SUMX creates a context transition on every row — the engine converts each row context into a filter context before evaluating the expression. For large tables, this multiplies the work dramatically.

// SLOW: Context transition on every row
SlowMeasure = 
SUMX(
    Sales,
    CALCULATE(SUM(Sales[Amount]))  ← unnecessary CALCULATE
)

// FAST: Aggregate directly
FastMeasure = SUM(Sales[Amount])

Use Variables to Avoid Repeated Evaluation

If a DAX measure references the same sub-expression multiple times, the engine evaluates it multiple times unless you store it in a variable. Variables evaluate once and reuse the result.

// SLOW: TotalSales evaluated twice
Margin% = DIVIDE(SUM(Sales[Profit]), SUM(Sales[Amount]))
               + DIVIDE(1, SUM(Sales[Amount]))  ← evaluated again

// FAST: Use VAR to evaluate once
Margin% = 
VAR TotalSales = SUM(Sales[Amount])
RETURN DIVIDE(SUM(Sales[Profit]), TotalSales)
        + DIVIDE(1, TotalSales)

Reducing Visual Load Time

Each visual on a report page sends its own query to the data model when the page loads. A page with 15 visuals sends 15 simultaneous queries. Use these techniques to reduce the query load on each page.

First, limit visuals per page to eight or fewer. Split complex pages into two pages with a button navigation between them. Second, remove visuals that users rarely look at — if a visual is not driving decisions, it is just slowing down the page. Third, use Bookmarks to toggle between different chart views rather than stacking multiple charts on the same page.

Dataverse Performance Optimization

Dataverse is the fastest and most capable data source for Power Platform, but it still responds to how well you design your tables and queries.

Indexing for Fast Lookups

Dataverse automatically indexes the primary key column. Any other column you frequently filter, sort, or join on should be manually indexed. Go to the table definition in make.powerapps.com, select the column, and enable the Searchable property. This tells Dataverse to build and maintain a search index for that column.

┌────────────────────────────────────────────────────────────────┐
│                 INDEXING BENEFIT DIAGRAM                       │
│                                                                │
│  Table: 500,000 Order records                                  │
│                                                                │
│  Query: Filter where Status = "Pending"                        │
│                                                                │
│  WITHOUT index on Status column:                               │
│  Dataverse scans all 500,000 rows → checks Status → returns    │
│  Time: ~800ms                                                  │
│                                                                │
│  WITH index on Status column:                                  │
│  Dataverse reads index → jumps directly to Pending rows        │
│  Time: ~40ms                                                   │
└────────────────────────────────────────────────────────────────┘

Retrieving Only the Columns You Need

When Power Apps or Power Automate queries Dataverse, the default behavior retrieves all columns for every row. If a table has 50 columns and you only need 3, the system still transfers all 50. Use the ShowColumns function in Power Apps to restrict which columns load, and use the Select columns option in Power Automate's Dataverse actions.

Using Views Instead of Filter Formulas

Dataverse views are server-side filters defined in the data layer. When your app or flow uses a saved Dataverse view as its data source, Dataverse applies the filter before sending any data. This is always faster than sending all rows to Power Apps and filtering there with a formula.

Troubleshooting Power Platform Issues

Troubleshooting requires a systematic approach. Randomly changing things hoping something fixes the problem wastes time and often introduces new issues. Use these structured methods for each tool.

Power Apps Troubleshooting

Reading the Monitor Tool

The Power Apps Monitor tool is your best diagnostic instrument. Open it from the Advanced tools menu in make.powerapps.com while your app is in preview mode. It shows every network call the app makes, the formula that triggered it, how long it took, and the full request and response data.

┌────────────────────────────────────────────────────────────────┐
│              POWER APPS MONITOR TOOL OUTPUT                    │
│                                                                │
│  Operation          Duration   Status   Result                 │
│  ──────────────     ────────   ──────   ──────                 │
│  App.OnStart        2,341 ms   ✓ OK     -                      │
│  GetItems (SP)        843 ms   ✓ OK     42 records             │
│  LookUp (SP)        1,200 ms   ✓ OK     1 record  ← suspicious │
│  LookUp (SP)        1,198 ms   ✓ OK     1 record  ← repeated!  │
│  LookUp (SP)        1,201 ms   ✓ OK     1 record  ← 100 times  │
│                                                                │
│  Finding: LookUp running inside gallery (100 rows)             │
│  Fix: Pre-join data with AddColumns before binding gallery     │
└────────────────────────────────────────────────────────────────┘

Sort the Monitor output by Duration to find the slowest operations first. Look for the same operation repeating many times — that pattern always points to a formula inside a loop or gallery.

Common Power Apps Errors and Fixes

Error: "Delegation warning — formula might not work correctly for large data sets" — You are using a non-delegable formula. Rewrite it using a delegable function or move the logic to Power Automate.

Error: "Something went wrong — Error: 429" — Your app hit the connector's rate limit. Add exponential backoff by wrapping the call in an If(IsError(...), Notify("Too many requests, try again"), result) pattern.

Error: Data not refreshing after form submit — Power Apps caches gallery data. Call Refresh(DataSourceName) in the form's OnSuccess property to force the gallery to reload from the source.

Error: "The specified column does not exist" — The column was renamed or deleted in the data source. Remove the data source connection in Power Apps, reconnect it, and update any formulas that referenced the old column name.

Power Automate Troubleshooting

Reading Run History

Every flow keeps a run history showing each execution. Click any run to see a detailed view of every action — which ones succeeded (green), which ones failed (red), and how long each one took. Failed actions expand to show the exact error message and the input and output data at the moment of failure.

┌────────────────────────────────────────────────────────────────┐
│              FLOW RUN HISTORY DIAGNOSTIC                       │
│                                                                │
│  Flow: Process New Orders                                      │
│  Run: 2026-06-04 09:15 AM  ●FAILED  Duration: 4m 12s           │
│                                                                │
│  ✓ Trigger: When item created         0.2s                     │
│  ✓ Get item details                   0.8s                     │
│  ✓ Condition: Is order > $100         0.0s                     │
│    ✓ Yes branch                                                │
│      ✓ Get customer record            1.1s                     │
│      ✗ Send email                     FAILED                   │
│        Error: "The email address is invalid"                   │
│        Input: customer_email = null                            │
│                                                                │
│  Root cause: Customer record has no email address              │
│  Fix: Add null check before send email action                  │
└────────────────────────────────────────────────────────────────┘

Using Compose to Debug Expression Values

When a complex expression produces unexpected results, add a Compose action immediately after it and pass the expression as the input. Run the flow and inspect the Compose output in the run history to see exactly what value the expression produced at that point. This technique lets you isolate exactly where data goes wrong in a long chain of actions.

Common Power Automate Errors and Fixes

Error: "The caller with object id does not have permission" — The connection used by the flow does not have access to the resource. Edit the flow connection and sign in with an account that has the right permissions, or ask the resource owner to grant access.

Error: "Flow save failed — action references a missing trigger output" — A dynamic content expression references a field that no longer exists in the trigger schema. Check the trigger and verify the field name matches exactly what the data source sends.

Error: Flow runs but produces no output — The trigger condition or scope condition is filtering out all records. Add Compose actions at the start of the flow to log the trigger body and verify the data is arriving as expected.

Error: "WorkflowTriggerThrottled" — The flow is triggering too frequently. Add a condition at the start to skip runs that do not meet your criteria, or switch from a recurrence trigger to an event-based trigger so the flow only runs when data actually changes.

Power BI Troubleshooting

Using Performance Analyzer

The Performance Analyzer pane in Power BI Desktop records how long each visual takes to render when the page loads. Open it from the View menu, click Start Recording, then refresh the page. The analyzer shows DAX query time, visual display time, and total time for each visual.

┌────────────────────────────────────────────────────────────────┐
│             POWER BI PERFORMANCE ANALYZER RESULTS              │
│                                                                │
│  Visual                  DAX Query   Visual   Total            │
│  ───────────────────     ─────────   ──────   ─────            │
│  Sales by Region map       45ms       62ms    107ms  ✓ Fast    │
│  Monthly trend chart       82ms       34ms    116ms  ✓ Fast    │
│  Customer detail table  3,840ms      120ms  3,960ms  ✗ Slow    │
│  Top 10 products           91ms       28ms    119ms  ✓ Fast    │
│                                                                │
│  Finding: Customer detail table DAX is taking 3.8 seconds      │
│  Action: Copy DAX query → paste into DAX Studio for analysis   │
└────────────────────────────────────────────────────────────────┘

Click the arrow next to a slow visual to copy its DAX query. Paste it into DAX Studio (a free external tool) to run it with detailed timing breakdowns and find exactly which part of the measure is slow.

Common Power BI Errors and Fixes

Error: "Query timeout expired" — A DirectQuery report is asking the source database a question that takes too long. Add indexes to the database columns used in filters, or switch to Import Mode.

Error: "Refresh failed — credentials are out of date" — The gateway or cloud credential used for scheduled refresh has expired. Go to the dataset settings in the Power BI Service, expand Data source credentials, and re-enter the credentials.

Error: Relationship shows a warning icon in the model view — The relationship has ambiguous paths (multiple paths to the same table) or a many-to-many relationship without a bridge table. Review the data model and add a bridge table, or change the relationship cardinality to resolve the ambiguity.

Error: Measure returns blank when it should return a number — The filter context is removing all rows before the measure evaluates. Wrap the measure with CALCULATE(measure, REMOVEFILTERS()) to test it without any filter applied, then narrow down which filter is causing the blank.

Dataverse Troubleshooting

Using the Dataverse Audit Log

Dataverse keeps an audit log of all data changes when auditing is enabled on a table. If records are disappearing, changing unexpectedly, or getting created in error, the audit log shows who made each change, when, and what the values were before and after. Enable auditing on tables where data integrity is critical.

Common Dataverse Errors and Fixes

Error: "You do not have permission to perform this action" — The user's security role does not include the required privilege. Go to the environment's security roles in the Admin Center, find the user's assigned role, and add the missing Create, Read, Write, or Delete privilege for the relevant table.

Error: "A record with matching key values already exists" — A duplicate detection rule or alternate key constraint is blocking the insert. Check if the record already exists using a lookup before attempting to create it, or update the existing record instead.

Error: Calculated column shows wrong values after data import — Calculated columns do not recalculate automatically after bulk imports through data migration tools. Run a bulk update job on the table to trigger recalculation, or use a real-time workflow to keep calculated values current.

Building a Performance-First Mindset

The best time to fix a performance problem is before you create it. These habits cost you nothing during the build and save hours of rework later.

The Performance Checklist

┌────────────────────────────────────────────────────────────────┐
│           POWER PLATFORM PERFORMANCE CHECKLIST                 │
├────────────────────────────────────────────────────────────────┤
│  POWER APPS                                                    │
│  □ No LookUp or Filter inside gallery properties               │
│  □ Reference data loaded into collections at app start         │
│  □ Concurrent used for multiple data loads                     │
│  □ No delegation warnings in production screens                │
│  □ Gallery Items use delegable Filter formula                  │
│  □ Screen OnVisible only loads data needed for that screen     │
├────────────────────────────────────────────────────────────────┤
│  POWER AUTOMATE                                                │
│  □ No connector calls inside loops (unless per-item required)  │
│  □ Concurrency enabled for Apply to Each (where safe)          │
│  □ Retry policy set on all connector actions                   │
│  □ Variables replaced with Compose where possible              │
│  □ Flow tested with large data set, not just 3 test records    │
├────────────────────────────────────────────────────────────────┤
│  POWER BI                                                      │
│  □ Import Mode used (not DirectQuery) unless truly needed      │
│  □ Star schema implemented                                     │
│  □ No flat tables with repeated text columns                   │
│  □ Page has fewer than 8 visuals                               │
│  □ Performance Analyzer shows no visual over 1 second          │
│  □ DAX measures use VAR for repeated expressions               │
├────────────────────────────────────────────────────────────────┤
│  DATAVERSE                                                     │
│  □ Frequently filtered columns are marked Searchable           │
│  □ Power Apps uses ShowColumns to limit column retrieval       │
│  □ Dataverse Views used as data source where possible          │
│  □ Auditing enabled on critical tables                         │
└────────────────────────────────────────────────────────────────┘

Testing at Scale Before You Deploy

Performance problems almost never appear during development because developers test with small amounts of data. An app tested with 50 records may perform flawlessly, then crawl with 10,000 records in production because of a non-delegable formula that was silently capping results.

Before deploying any Power Platform solution, test it with data volumes at least equal to what production will hold in twelve months — not today's volume. Load test your flows by running them against the full production data set in a test environment. Check Power BI performance with the complete historical dataset, not a sample.

Setting Up Monitoring After Deployment

Performance degrades gradually as data grows and as users add more records. Set up monitoring so you know about problems before users complain.

For Power Apps, use the Power Platform Admin Center Analytics page to track app load times, error rates, and active user counts by day. For Power Automate, use the Flow Analytics dashboard to monitor run durations and failure rates. For Power BI, use the Premium Metrics App (for Premium workspaces) or the Usage Metrics Report in any workspace to track report load times and user activity.

Key Points

  • Delegation is the most important Power Apps performance concept — a delegation warning means your app is silently returning incomplete data for large data sets.
  • Use Concurrent and collections in Power Apps to load data in parallel and reduce data source calls from dozens to one.
  • Never place LookUp or Filter formulas inside gallery properties — pre-join data into collections using AddColumns before binding to the gallery.
  • Move actions that do not depend on the current loop item outside of Apply to Each loops in Power Automate to cut run times and avoid throttling.
  • Enable concurrency on Apply to Each loops when actions are independent — this can reduce loop execution time by 10x or more.
  • Power BI performs best with Import Mode and a star schema data model — flat tables with repeated text values are the most common cause of slow reports.
  • Use the Power Apps Monitor tool, Power Automate run history, and Power BI Performance Analyzer to find the exact cause of any performance problem before attempting a fix.
  • Always test your Power Platform solutions with production-scale data volumes before deploying — small test data sets hide delegation and performance issues.

Leave a Comment