Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ codeunit 50493 "Perf Record Clone Bad"
Customer: Record Customer;
CustomerCopy: Record Customer;
begin
Customer.SetLoadFields("Credit Limit (LCY)");
Customer.SetFilter("Credit Limit (LCY)", '>0');
Customer.SetLoadFields("Credit Limit (LCY)");
if Customer.FindSet(true) then
repeat
CustomerCopy.Copy(Customer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ codeunit 50492 "Perf Record Clone Good"
var
Customer: Record Customer;
begin
Customer.SetLoadFields("Credit Limit (LCY)");
Customer.SetFilter("Credit Limit (LCY)", '>0');
Customer.SetLoadFields("Credit Limit (LCY)");
if Customer.FindSet(true) then
repeat
Customer.Validate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ codeunit 50100 "Item Reindex Queue"
ReindexQueue: Codeunit "Reindex Queue";
begin
// Only the primary key is used in the loop body; load nothing else.
Item.SetLoadFields("No.");
Item.SetRange("Item Category Code", CategoryCode);
Item.SetLoadFields("No.");

if Item.FindSet() then
repeat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ codeunit 50491 "Perf AutoCalcFields Bad"
var
Customer: Record Customer;
begin
Customer.SetLoadFields("Credit Limit (LCY)");
Customer.SetFilter("Credit Limit (LCY)", '>0');
Customer.SetLoadFields("Credit Limit (LCY)");
if Customer.FindSet() then
repeat
Customer.CalcFields("Balance (LCY)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ codeunit 50490 "Perf AutoCalcFields Good"
var
Customer: Record Customer;
begin
Customer.SetLoadFields("Credit Limit (LCY)");
Customer.SetFilter("Credit Limit (LCY)", '>0');
Customer.SetLoadFields("Credit Limit (LCY)");
Customer.SetAutoCalcFields("Balance (LCY)");
if Customer.FindSet() then
repeat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ codeunit 50218 "Perf Sample LoadFields Good"
var
Customer: Record Customer;
begin
Customer.SetLoadFields(Name);
Customer.SetRange("Country/Region Code", 'US');
Customer.SetLoadFields(Name);
if Customer.FindSet() then
repeat
Message(Customer.Name);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
bc-version: [all]
domain: performance
keywords: [setloadfields, partial-record, normal-field, flowfield, get, findset]
keywords: [setloadfields, partial-record, normal-field, flowfield, get, findset, statement-order]
technologies: [al]
countries: [w1]
application-area: [all]
Expand All @@ -11,16 +11,18 @@ application-area: [all]

## Description

`SetLoadFields(...)` declares the subset of normal fields the next read should materialize, "reducing data read and transfer thereby improving performance significantly." Per the upstream guidance, "the gains scale with the amount of rows read, so for loops that read many rows `SetLoadFields` is even more important." Primary-key fields, `SystemId`, and system audit fields are loaded automatically, "and fields that are filtered on are also automatically included" — those do not need to appear in the list. `SetLoadFields` only affects `FieldClass = Normal`; it does not narrow FlowFields or FlowFilters.
`SetLoadFields(...)` declares the subset of normal fields the next read should materialize, "reducing data read and transfer thereby improving performance significantly." Per the upstream guidance, "the gains scale with the amount of rows read, so for loops that read many rows `SetLoadFields` is even more important." Primary-key fields, `SystemId`, and system audit fields are loaded automatically, "and fields that are filtered on are also automatically included" — those do not need to appear in the list. `SetLoadFields` only affects `FieldClass = Normal`; it does not narrow FlowFields or FlowFilters. Its position relative to `SetRange`/`SetFilter` does not change the projection: filtered fields are added to the load set at read time either way. Only a fieldless `SetLoadFields()` — which resets the selection to all readable normal fields — or a later `SetLoadFields(...)` overwriting an earlier one changes what is loaded.

## Best Practice

Before a `Get`, `FindSet`, or `FindFirst` that the procedure follows by reading only a handful of the table's fields, call `SetLoadFields` listing exactly those fields. The pattern `SetLoadFields(...); if Record.Get(...) then ...` is the upstream-endorsed shape. 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-need-no-access-optimization.md`, `temporary-tables-have-no-database-cost.md`). For report dataitems, use `AddLoadFields` in `OnPreDataItem` instead (see `addloadfields-in-report-onpredataitem.md`).
Before a `Get`, `FindSet`, or `FindFirst` that the procedure follows by reading only a handful of the table's fields, call `SetLoadFields` listing exactly those fields. The pattern `SetLoadFields(...); if Record.Get(...) then ...` is the upstream-endorsed shape. 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 so no intervening statement can reset it. 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-need-no-access-optimization.md`, `temporary-tables-have-no-database-cost.md`). For report dataitems, use `AddLoadFields` in `OnPreDataItem` instead (see `addloadfields-in-report-onpredataitem.md`).

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`.