Study guide

15.3 Performance Profiler, SetLoadFields & Query Optimization

Microsoft Dynamics 365 Business Central Developer MB-820

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Business Central Architecture & Platform Foundation

1.1 Business Central Architecture & Extensions Model 1.2 Customization Lifecycle: Cloud (SaaS) vs. On-Premises 1.3 Base Application, System Application & AppSource

2 Chapter 2: Development Environment & Configuration

2.1: Development Environment Setup: VS Code, AL: Go! Projects & Sandboxes 2.2: AL Configuration Files: app.json & launch.json Parameters 2.3: Multi-Root Workspaces & Project Dependencies

3 Chapter 3: Extension Lifecycle: Debugging, Deployment, Multilanguage & Maintenance

3.1 Debugging & Snapshot Debugging in Visual Studio Code 3.2 Extension Deployment & Schema Synchronization Modes 3.3 Multilanguage Development with XLIFF & Translation Files 3.4 Extension Maintenance, Deprecation & Breaking Changes

4 Chapter 4: Tables, Table Extensions & Data Modeling

4.1: Building Tables, Fields, Keys & Data Types 4.2: Table Extensions & Table Modifications 4.3: FlowFields, FlowFilters & Table Relations 4.4: Enums, Enum Extensions & Extensible Types

5 Chapter 5: Pages, Page Extensions & Role Centers

5.1: Page Types, Anatomy & Control Structure 5.2: Building Card, List & Document Pages 5.3: Page Extensions & Page Customizations 5.4: Role Centers, Headlines & Cue Data Modeling

6 Chapter 6: Reports & Document Generation

6.1 Report Architecture, DataItems & Dataset Design 6.2 Report Layouts: RDLC, Word, Excel & Multilanguage 6.3 Document Reports & Request Page Programming 6.4 Processing-Only Reports & Report Substitutions

7 Chapter 7: XMLports & Data Exchange

7.1 XMLport Architecture, Formats & Properties 7.2 XMLport Node Hierarchy, Triggers & Stream Manipulation

8 Chapter 8: Codeunits, Events, Triggers & Interfaces

8.1 Codeunit Types, Execution & SingleInstance Codeunits 8.2 Events, Publishers, Subscribers & Event Isolation 8.3 Interfaces, Polymorphism & Dynamic Codeunit Invocation 8.4 Installation & Upgrade Codeunits, Data Transfer & Archive

9 Chapter 9: Entitlements, Permissions & Queries

9.1 Permission Sets & Permission Set Extensions 9.2 Inherent Permissions, Inherent Entitlements & Security Scoping 9.3 Query Objects: Joins, Aggregation & Query as Report Data Source

10 Chapter 10: UI Customization, User Assistance & Onboarding

10.1 Profile Objects & Custom Page Views in AL 10.2 User Assistance: ToolTips, Teaching Tips & In-App Tours 10.3 Assisted Setup, Guided Experience & Onboarding Checklists

11 Chapter 11: Business Central Design Patterns & Data Process Model

11.1 Functional Table Types: Master Data, Supplemental & Setup Patterns 11.2 Document Standards: Header, Line, History & Journal Architectures 11.3 Data Process Model & Posting Routine Architecture

12 Chapter 12: AL Language Fundamentals, Data Types & Variables

12.1 AL Syntax, Variable Scope, Primitive & Complex Data Types 12.2 Expressions, Control Flow Statements & Built-in Functions 12.3 Access Modifiers (Public, Internal, Local) & Code Scoping

13 Chapter 13: Data Manipulation, Streams & Error Handling

13.1 Record Operations: Get, FindSet, ModifyAll & Filter Functions 13.2 Streams, File Management & TempBlob 13.3 Error Handling: ErrorInfo, TryFunctions & Collectible Errors

14 Chapter 14: Testing, Test Toolkit & Automation

14.1 Testing Architecture & the Test Toolkit 14.2 Authoring Test Codeunits & UI Handler Functions

15 Chapter 15: Telemetry, Performance Optimization & Analyzers

15.1 Telemetry Configuration & Azure Application Insights 15.2 Custom Telemetry Signals with Session.LogMessage & KQL 15.3 Performance Profiler, SetLoadFields & Query Optimization 15.4 AL Analyzers: CodeCop, AppSourceCop, UICop & PTECop

16 Chapter 16: REST Web Services & JSON in AL

16.1 HttpClient, HttpRequestMessage & REST API Consumption 16.2 JSON Processing: JsonObject, JsonArray, JsonValue & JsonToken

17 Chapter 17: API Pages, OData, Read Scale-Out & OAuth

17.1 API Pages (PageType=API), OData Web Services & REST Endpoints 17.2 Bound and Unbound OData Actions with [ServiceEnabled] 17.3 Read Scale-Out Architecture & DataAccessIntent Configuration 17.4 Microsoft Entra ID App Registrations & OAuth 2.0 Integration

15.3 Performance Profiler, SetLoadFields & Query Optimization

Key Takeaways Explain This Topic AI

The in-client Performance Profiler in the Web Client enables users and developers to record interactive browser sessions, identify hot paths, and export .alcpuprofile files for deep analysis.

VS Code AL Performance Profiling supports snapshot profiling and flame graph visualization to pinpoint slow methods and costly database operations.

Partial records (SetLoadFields, AddLoadFields, AreFieldsLoaded) optimize data access by loading only specified fields and skipping unnecessary SQL joins with companion tables.

When looping over records with repeat...until, developers must use FindSet() with appropriate buffering parameters (ForUpdate, UpdateKey) and avoid executing CalcFields inside the loop body.

SQL concurrency is optimized by selecting appropriate ReadIsolation levels (such as ReadUncommitted for reporting) and keeping transactional write locks as short as possible.

Last updated: August 2026

15.3 Performance Profiler, SetLoadFields & Query Optimization

Optimizing code performance and database access is a core competency evaluated on the MB-820 exam. In a cloud ERP environment, inefficient AL code and unoptimized SQL statements cause slow user response times, lock contention, and high compute consumption. Developers must master the built-in profiling tools, apply partial record optimizations, utilize efficient index cursors, and control transaction locking boundaries.

1. Business Central Performance Profiling Tools

Business Central provides two complementary performance profiling mechanisms: the In-Client Performance Profiler (Web Client) and the AL Performance Profiler in Visual Studio Code. +-----------------------------------------------------------------------+

  • | IN-CLIENT PERFORMANCE PROFILER |
  • | |
  • | 1. User opens 'Performance Profiler' page in Web Client. |
  • | 2. Clicks 'Start' to begin recording the active session. |
  • | 3. Executes slow business action (e.g., Post Sales Order). |
  • | 4. Clicks 'Stop' -> Web Client renders Call Tree & Top Time by App. |
  • | 5. Clicks 'Download' -> Generates an '.alcpuprofile' capture file. |
  • +-----------------------------------┬-----------------------------------+
  • │ (Import .alcpuprofile)
  • ▼
  • +-----------------------------------------------------------------------+
  • | VISUAL STUDIO CODE AL PROFILER VIEWS |
  • | |
  • | - Top Down View (Call Tree hierarchy with Self Time vs Total Time) |
  • | - Bottom Up View (Hot Path list sorted by most expensive methods) |
  • | - Flame Graph Visualization (Call stack width = execution time) |
  • | - Direct Source Code Line Profiling (Time spent per AL code line) |
  • +-----------------------------------------------------------------------+
  • 1. The In-Client Web Profiler

Accessibility: Available directly within the Business Central Web Client ( Help & Support -> Analyze Performance / Performance Profiler ).

Non-Technical User Friendly: Functional consultants and end users can record slow business operations in production without installing developer tools.

Call Tree Analysis: Displays the exact hierarchy of executed objects, total time spent per extension (attributing performance cost to specific AppSource or Per-Tenant extensions), and top time-consuming AL procedures.

Profile Export: The recorded trace can be downloaded as an .alcpuprofile file and shared with developers.

2. VS Code AL Performance Profiler & Snapshot Profiling

Snapshot Profiling: Developers initialize a snapshot debugging session in launch.json ( "mode": "snapshot" ), record the user session, and download the execution profile.

Analysis Views: When an .alcpuprofile file is opened in VS Code, the AL Language extension renders:

Top Down View: Hierarchical call tree showing caller-to-callee relationships.

Bottom Up View: Inverted call stack grouping execution time by leaf procedures to highlight hot paths.

Flame Graph: Visual representation where horizontal width corresponds to execution duration.

Line-Level Attribution: Highlights individual lines of AL code with execution counts and self-time.

Loading diagram... Data Access Layer: Full Table Join vs Partial Records Optimization

2. Partial Records Optimization: SetLoadFields

In standard AL table operations, invoking Rec.FindSet() or Rec.Get() instructs the Data Access Layer to load all fields in the table schema across the network, automatically executing SQL LEFT OUTER JOIN statements against every installed companion table (table extensions).

The Partial Records API

The Partial Records API allows developers to restrict database I/O to only the fields required for the specific business calculation: local procedure CalculateTotalCustomerBalance(): Decimal

  • var
  • Customer: Record Customer;
  • TotalBalance: Decimal;
  • begin
  • // 1. Specify only the fields needed for the calculation
  • Customer.SetLoadFields("No.", "Balance (LCY)");
  • if Customer.FindSet() then
  • repeat
  • TotalBalance += Customer."Balance (LCY)";
  • until Customer.Next() = 0;
  • exit(TotalBalance);
  • end;
  • Partial Records Methods

Rec.SetLoadFields([Field1, Field2, ...]) : Replaces the active load field list on the record variable. Primary key fields are always loaded automatically and do not need to be specified.

Rec.AddLoadFields([Field3, ...]) : Appends additional fields to an already configured partial record load list.

Rec.AreFieldsLoaded([Field1, ...]) : Returns a Boolean indicating whether all specified fields are currently present in the in-memory record buffer.

Just-In-Time (JIT) Loading: If AL code attempts to read a field that was not included in SetLoadFields , the runtime transparently executes a background SQL query (a JIT fetch) to retrieve the remaining fields. While functionally safe, excessive JIT fetches cause "chatty" database round-trips and degrade performance.

3. Record Navigation & Iteration Optimization

Iterating over database records in AL requires selecting optimal cursors, buffering parameters, and key sorting.

1. FindSet Buffering Parameters

The FindSet() method accepts two optional boolean parameters: Record.FindSet(ForUpdate: Boolean, UpdateKey: Boolean)

Parameter Default Purpose & Recommended Usage

ForUpdate false When true , signals to the NST that the transaction intends to modify the retrieved records ( Rec.Modify() ), applying appropriate SQL row-locking hints and avoiding lock escalations.

UpdateKey false When true , informs the database engine that fields belonging to the current sorting key or primary key will be modified during the loop, ensuring the cursor remains stable.

2. Method Selection Guide: FindFirst vs. FindSet vs. IsEmpty

  • Scenario / Requirement Recommended Method Prohibited / Unoptimized Pattern
  • Iterating over multiple records Rec.FindSet() Rec.Find('-') (Legacy C/SIDE pattern; unoptimized cursor)

Reading exactly one record Rec.FindFirst() or Rec.FindLast() Rec.FindSet() (Allocates unnecessary multi-row buffer)

Checking if matching records exist if not Rec.IsEmpty() then if Rec.FindFirst() then or if Rec.Count() > 0 then

  • Counting record occurrences Rec.Count() Reading all records with repeat...until counter
  • 3. Avoiding CalcFields Inside Large Loops

Invoking Rec.CalcFields(FlowField) inside a loop over 50,000 ledger lines executes an individual SQL aggregation subquery on every single iteration (creating an N+1 query problem). To optimize:

Use Query objects ( QueryType = Normal ) to perform bulk SQL SUM and GROUP BY operations in a single database round-trip.

Ensure appropriate SumIndexField Technology ( SIFT ) keys are defined on the underlying ledger tables so the database engine reads pre-aggregated index values instead of scanning physical rows.

4. SQL Concurrency, Locking & ReadIsolation

High-volume cloud ERP systems require strict isolation management to prevent deadlocks and lock timeouts ( RT0012 ).

1. Explicit ReadIsolation Levels

AL allows developers to set the transaction isolation level on individual Record variables using the ReadIsolation property/method: Customer.ReadIsolation := IsolationLevel::ReadUncommitted;

  • Customer.SetRange("Blocked", Customer.Blocked::" ");
  • TotalActiveCustomers := Customer.Count();

Isolation Level Dirty Reads Allowed? Locking Behavior Best Use Case

ReadUncommitted Yes Does not acquire shared read locks; never blocked by concurrent write transactions. Tile Cues, Role Center counters, analytical reports, background telemetry queries.

ReadCommitted No Default read level. Reads only committed data. Standard transactional lookups and validation checks.

RepeatableRead No Holds shared read locks until transaction completes. Strict ledger consistency where concurrent updates must be blocked.

UpdLock No Places update locks on rows immediately upon reading. Pre-locking ledger entries prior to posting to completely prevent deadlocks.

2. Minimizing Transaction Duration

Postpone Writes: Perform all external REST API calls, user confirmation dialogs ( Confirm ), and in-memory calculations before issuing the first Rec.Insert() , Rec.Modify() , or Rec.Delete() .

Eliminate UI in Transactions: Never invoke modal pages or Confirm() dialogs while a database write transaction is open; if the user steps away from their computer, all locked database tables remain frozen across the entire company.