- performance/use-setloadfields-for-partial-records: Clarify that filter-only fields (SetRange/SetFilter) do not need to be listed in SetLoadFields — the DB resolves them via the index without hydrating the value into AL memory. - performance/avoid-calcfields-in-loops: Add explicit exception for OnAfterGetRecord and OnValidate triggers, which are platform-managed and not developer-authored loops. - performance/split-read-only-and-write-paths-to-avoid-locktable: Add ReadIsolation as the primary recommendation for read-only paths; LockTable reserved for confirmed write paths only. - performance/prefer-direct-record-over-recordref: Scope the finding to hot unbounded loops (10k+ rows) over ledger-entry-scale tables; RecordRef in bounded/admin/setup contexts is not a concern. - upgrade/enum-changes-must-be-additive-at-the-end: Replace direct ObsoleteState = Removed guidance with the two-stage workflow (Pending first, Removed later); reference use-obsolete-pending-before-removed. - upgrade/use-datatransfer-for-large-dataset-initialization: Add the >300,000 records threshold as the concrete trigger for requiring DataTransfer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1.6 KiB
| bc-version | domain | keywords | technologies | countries | application-area | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
performance |
|
|
|
|
Do not call CalcFields inside loops
Description
CalcFields evaluates one or more FlowFields for the current record by issuing a separate SQL aggregation. Called inside a loop over a record set, it becomes an N+1 problem: one aggregate per row. For any non-trivial set on a ledger-entry-backed FlowField this is orders of magnitude slower than the equivalent batched query.
Best Practice
Move CalcFields out of the iteration. If the total is what you need, use CalcSums on the filtered parent set. If row-by-row FlowField values are needed, reshape the computation so the aggregate runs once — for example by joining against a temporary table populated in a single batched query.
Acceptable exceptions: CalcFields inside an OnAfterGetRecord page trigger is the standard pattern for displaying computed FlowField values — the platform calls this trigger once per row and it is not a developer-authored loop. Similarly, CalcFields inside an OnValidate field trigger fires at most once per user action and is acceptable. The concern is only developer-written FindSet … repeat … until Next() = 0 loops.
See sample: avoid-calcfields-in-loops.good.al.
Anti Pattern
Calling CalcFields inside repeat ... until Next() = 0 on a hot parent record is the textbook N+1 pattern. Even a modest parent set size (hundreds of rows) turns into thousands of round-trips.
See sample: avoid-calcfields-in-loops.bad.al.