bcquality/microsoft/knowledge/performance/table-event-subscribers-disable-bulk-modifyall-and-deleteall.md
Jesper Schulz-Wedde 800e266bfe Add seven performance knowledge articles from BC developer guidance
Cover non-obvious platform behaviors a capable LLM reliably gets wrong:
hidden FlowFields still calculate, LockTable scopes to the whole table,
query objects bypass the primary-key cache, table-event subscribers
disable bulk ModifyAll/DeleteAll, Blob fields are uncached, OnCompanyOpen
subscribers block every session creation, and the test framework
disables bulk insert mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:38:28 +02:00

1.9 KiB

bc-version domain keywords technologies countries application-area
all
performance
event
subscriber
modifyall
deleteall
bulk
row-by-row
al
w1
all

Table event subscribers force ModifyAll and DeleteAll to run row-by-row

Description

ModifyAll and DeleteAll normally compile to a single set-based SQL UPDATE or DELETE. That optimization is conditional: if any subscriber is bound to the table's modify or delete events — OnBeforeModifyEvent, OnAfterModifyEvent, OnBeforeDeleteEvent, OnAfterDeleteEvent, and their Rec counterparts — the server must invoke AL per affected row so the subscriber sees each record. The operation falls back to a row-by-row loop, one SQL statement per row, inside the same transaction.

The slowdown is invisible in the caller's source: the call site still reads as a bulk operation. It only shows up under load, and adding an apparently cheap subscriber (even an empty one, or one that guards on a condition and returns) is enough to trigger the fallback for every caller of ModifyAll/DeleteAll on that table across the system. Central tables — Item Ledger Entry, G/L Entry, Sales Line — are the worst places to attach such subscribers because every extension's bulk operation pays the cost.

Best Practice

Before subscribing to a table's modify or delete events, consider whether the logic can live elsewhere — on the triggering action, on a specific OnValidate, or on a business-event publisher. If the subscriber is unavoidable, scope it as narrowly as possible and document that it forces row-by-row execution so future maintainers understand the cost. Watch PRs that add such subscribers to heavily-modified tables.

Anti Pattern

An empty or nearly-empty OnAfterModifyEvent subscriber on Sales Line added as a placeholder for future integration. Every ModifyAll on Sales Line — in the base app, in every extension, in every tenant — now runs one SQL UPDATE per row.