Practical coding tips to Improve performance

 

Practical Coding Performance Tips

Improving performance in Dynamics 365 NAV/Business Central (AL or C/AL language where applicable) requires a combination of smart coding practices, efficient data access, and leveraging platform features. Here are practical AL coding tips and tricks specifically aimed at improving performance:

Limit the Scope of SETFILTER and SETRANGE

  • Only filter the fields you need to reduce record scanning.

        Customer.SETRANGE("Country/Region Code", 'GB');

    Avoid:
        Customer.FINDSET();

    Use instead:

        IF Customer.FINDFIRST THEN;

   FINDSET loads multiple records; use FINDFIRST if only one record is needed.

Use SetAutoCalcFields Wisely

    Avoid automatic calculation of flow fields (like Amount, Balance) unless you need them.

    Customer.SetAutoCalcFields("Balance");

    Note: Use only the fields you actually need to avoid unnecessary SQL hits

Use Temporary Tables When Possible

Avoid hitting the database multiple times by working with temporary in-memory copies.

TempSalesLine.RESET();
TempSalesLine.SETRANGE("Document Type", "Document Type"::Order);
TempSalesLine.TEMPORARY := TRUE;
OR
TempCustomer: Record Customer temporary;

Avoid Unnecessary Loops

Minimize looping through large data sets. Use aggregation or count queries.

Customer.CALCSUMS("Balance");
This avoids having to loop through all entries to calculate totals.

Use MODIFYALL, DELETEALL, INSERTALL for Bulk Operations

These are more efficient than updating/deleting records one at a time in a loop.

    Slower:

REPEAT
Customer.Blocked := Customer.Blocked::All;
Customer.MODIFY(TRUE);
UNTIL Customer.NEXT = 0;

    Faster:

Customer.MODIFYALL(Blocked, Customer.Blocked::All);

Use IsEmpty to Avoid Unnecessary Loops

if not SalesLine.IsEmpty then begin
// Only process if lines exist
end;

Use MARK and MARKEDONLY for Bulk Filters

Good for tagging data before processing.

REPEAT
IF Condition THEN
Rec.MARK(TRUE);
UNTIL Rec.NEXT = 0;

Rec.MARKEDONLY(TRUE); 


Avoid Using SLEEP or Long UI Locks

Avoid delays and unnecessary SLEEP calls, which tie up the UI and server threads.

Use TESTFIELD Efficiently

Don’t overuse TESTFIELD in loops—it adds unnecessary checks.

Set Keys Appropriately

Define and use proper primary and secondary keys. Index fields based on common filters and sorts.

Customer.SETCURRENTKEY("Country/Region Code", "Customer Posting Group");

Minimize Use of FlowFields in Loops

FlowFields trigger lookups and calculations. Avoid them in tight loops—use CALCFIELDS once.

Customer.CALCFIELDS("Balance");
TotalBalance += Customer."Balance";

Use FINDSET(TRUE) When Modifying Records

FINDSET(TRUE) gives a lockable, modifiable set of records with fewer reads.

Avoid Find('-'), Find('+'), and Find('=') Unless Necessary

These can cause full table scans if not filtered well.

    Bad (Performance Hit):
Customer.Find('+');

    Better:

Customer.SetFilter("Customer Posting Group", '%1', 'DOMESTIC');
Customer.FindLast();

Reduce Usage of FieldRef and RecordRef

These dynamic types are powerful but slower than strongly typed records.


Avoid Calling Codeunit.Run Unnecessarily

If you're calling a Codeunit repeatedly, make it single-instance if possible, or cache results.

Set DataPerCompany = false if Applicable

For shared setup tables, avoid duplicating across companies.


Debugging & Profiling Tools

  • SQL Profiler: Track long-running SQL queries.

  • Application Insights (BC version): Can be configured to detect slow operations

That's all for this one. Comment below for your tips or tricks you’ve used in your own projects. I’d love to hear what’s worked for you.

Comments

Popular Posts