microsoft / microsoft/BCApps

Low-Level Code Calculator (codeunit 3687) is slow: processes items without a Production BOM and uses a List instead of a Dictionary

Open
#11,223 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Approved Team: SCM
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

  1. Filter the Item Production BOMs query on Production_BOM_No_ <> '' before opening it, so items without a Production BOM are never loaded/iterated.
  2. Change NodeKeysAddedToTree from List of [Text] to Dictionary of [Text, Boolean], giving near-constant lookup/insert (ContainsContainsKey, AddSet).
  3. Add an OnBeforeItemProductionBOMsOpen integration 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.