Low-Level Code Calculator (codeunit 3687) is slow: processes items without a Production BOM and uses a List instead of a Dictionary
Nobody has claimed this yet.
- Dominant language
- AL
- Stars
- 683
- Forks
- 459
- Avg merge
- 3d 26m
- Merged PRs (30d)
- 633
Description
Summary
The Low-Level Code Calculator (codeunit 3687 "Low-Level Code Calculator") performs poorly on databases with a large number of items and Production BOMs. In real-world scenarios a full low-level code calculation can take on the order of 10 hours, which is prohibitive for daily/background recalculation.
Two distinct issues contribute to the slowdown.
Problem 1 — Items without a Production BOM are processed unnecessarily (performance regression)
In PopulateFromItemAndRelatedBOMs, the Item Production BOMs query is opened filtered only on BOMStatus <> Closed:
ItemProductionBOMs.SetFilter(BOMStatus, '<>%1', Enum::"BOM Status"::Closed);
ItemProductionBOMs.Open();
Because of the way SetLoadFields is applied, the cache is invalidated for every item that does not have a Production BOM, so those items are loaded and iterated even though they can never contribute a parent/child relation to the BOM tree. On catalogs where only a small fraction of items have a Production BOM, the vast majority of the work is wasted.
Problem 2 — List is used where a Dictionary is required
The set of node keys already added to the tree is tracked with a List of [Text]:
NodeKeysAddedToTree: List of [Text];
Every membership check (NodeKeysAddedToTree.Contains(...)) and insert (.Add(...)) is an O(n) linear scan of the list. These calls happen once per node and per relation, so the total cost grows quadratically as the tree gets larger. On large BOM structures this dominates the runtime.
Proposed fix
- Filter the
Item Production BOMsquery onProduction_BOM_No_ <> ''before opening it, so items without a Production BOM are never loaded/iterated. - Change
NodeKeysAddedToTreefromList of [Text]toDictionary of [Text, Boolean], giving near-constant lookup/insert (Contains→ContainsKey,Add→Set). - Add an
OnBeforeItemProductionBOMsOpenintegration event so the query can be adjusted before it is opened.
Impact
The two changes are independent but complementary. In a real-world scenario the combination reduced full low-level code calculation time from roughly 10 hours to about 2 hours.
Affected object
src/Layers/W1/BaseApp/Manufacturing/ProductionBOM/LowLevelCodeCalculator.Codeunit.al— codeunit 3687"Low-Level Code Calculator"
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/Layers/W1/BaseApp/Manufacturing/ProductionBOM/LowLevelCodeCalculator.Codeunit.al, especially PopulateFromItemAndRelatedBOMs, the Item Production BOMs query, and NodeKeysAddedToTree. Apply the stated query filter, dictionary conversion, and integration event, then verify that items without Production BOMs are skipped and low-level code calculation behavior remains correct.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend, databases, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100