bcquality/microsoft/knowledge/performance/use-setloadfields-for-partial-records.md
Jesper Schulz-Wedde 87ba36e650
Add BC performance knowledge from OptimAL learnings (#198)
* Add BC performance knowledge from OptimAL learnings

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Address review feedback on performance guidance

Clarify predicate-supporting keys versus covering queries, demonstrate proven cache reuse, and evaluate the updated partial-load and bulk-update rules.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Jesper Schulz-Wedde <jesper.schulzwedde@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-29 17:21:28 +02:00

3.7 KiB

bc-version domain keywords technologies countries application-area
all
performance
setloadfields
partial-record
normal-field
flowfield
get
findset
statement-order
al
w1
all

Use SetLoadFields to load only the fields the code reads

Description

SetLoadFields(...) declares the subset of normal fields the next read should materialize. Microsoft's partial-record guidance explains how loading fewer fields reduces work, particularly for read loops and tables with extensions. Primary-key fields, SystemId, system audit fields, and fields being filtered on are loaded automatically; those do not need to appear in the selection. Only FieldClass = Normal fields can be selected, not FlowFields or FlowFilters.

Its position relative to SetRange/SetFilter does not change the projection: filtered fields are included at read time either way. Projection-changing operations are separate: AddLoadFields(...) expands the selection, a later SetLoadFields(...) or SetBaseLoadFields() overwrites it, and Reset() or a fieldless SetLoadFields() restores all readable normal fields. The Microsoft Learn references below document the selection and reset behavior.

Best Practice

Before a Get, FindSet, or FindFirst that the complete read path follows by reading only a handful of the table's fields, call SetLoadFields listing the normal fields used by the caller and its helpers. For example, SetLoadFields(...); if Record.Get(...) then ... selects fields before the read. Place the call immediately before the read, after any SetRange/SetFilter, so a reader can see at a glance which read the selection governs and any projection-changing operation is easy to spot. Check for later Reset and for unloaded fields read by a by-value helper; a JIT load can be served from cache, so it is not automatically a SQL round trip. Skip SetLoadFields when the table has few fields (under ten), when the code reads most of them (above 60 %), when the loop runs ten or fewer iterations, or when the table is exempt for other reasons (singleton setup tables, temporary tables). The numeric cutoffs are BCQuality review heuristics, not Microsoft platform thresholds. For report dataitems, use AddLoadFields in OnPreDataItem instead (see report partial loads).

See sample: use-setloadfields-for-partial-records.good.al.

Anti Pattern

Loading a wide table and reading one field per row in a loop. The bytes transferred per row are dominated by the columns the procedure does not touch; the SQL query selects them anyway. The same applies to a single Get on a wide table — the platform reads the whole row when a single field would have sufficed.

Statement order is not part of this anti pattern. SetLoadFields placed ahead of SetRange/SetFilter materializes exactly the same columns as the reverse order, so a reviewer reports it as a readability observation at most — never as a performance defect.

See sample: use-setloadfields-for-partial-records.bad.al.

References