bcquality/microsoft/knowledge/performance/avoid-commit-inside-loops.md
Jesper Schulz-Wedde e374a8a4b8 Bound commit checkpoints by key range
Use a capped ordered query to discover each checkpoint watermark before locking and processing only that key range.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 85be3fc4-5253-47b8-ba1b-6b8fd188fcea
2026-07-14 11:48:01 +02:00

2.2 KiB

bc-version domain keywords technologies countries application-area
all
performance
commit
loop
transaction
lock
checkpoint
bounded
watermark
topnumberofrows
codeunit-run
al
w1
all

Do not Commit inside loops

Contributions welcome — open a PR to refine or extend this article.

Description

Commit ends the current write transaction. Calling it inside a per-row loop produces one transaction per iteration and loses the ability to roll back the whole operation atomically; it also interferes with the platform's ability to batch write operations. Most loops need no explicit Commit at all — AL auto-commits the enclosing code module on successful completion (see understand-implicit-transaction-boundary.md). When the batch is too large for one transaction, the fix is not a per-row Commit but bounded checkpoints that each retrieve and process the next N rows.

Best Practice

If the batch is large enough that a single transaction is untenable, use an ordered primary-key watermark and retrieve a bounded next-N window. FindSet is optimized for reading the complete filtered set and isn't implemented as TOP X, so calling it over the remaining tail and breaking after N rows does not bound retrieval. The sample uses a query capped by TopNumberOfRows to discover the next upper key, then locks and processes only that key range. Commit after the bounded inner loop returns and persist its upper key as the next watermark. Use a stable key and define how a later run handles records inserted at or below an already committed watermark. A Codeunit.Run boundary can also own a chunk when its implicit commit and error behavior fit the caller — see codeunit-run-as-atomic-sub-operation.md.

See sample: avoid-commit-inside-loops.good.al.

Anti Pattern

Placing Commit inside repeat ... until Next() = 0 is almost always a mistake: it is unusual for the correctness of the operation to depend on per-row commits, and the cost of starting a new transaction on every row dominates the work.

See sample: avoid-commit-inside-loops.bad.al.