Skip to content

Nested loop causes quadratic performance degradation in SourceItem SaveMultiple #3463

Description

@stollr

The separateExistingAndNewItems method in Magento\Inventory\Model\ResourceModel\SourceItem\SaveMultiple uses a nested loop to match input source items against stored database rows.
When all items already exist in the database (a common scenario for periodic inventory syncs), this results in O(n × m) comparisons where n = input count and m = matching DB rows.

The problematic code:

// SaveMultiple.php — separateExistingAndNewItems()

foreach ($sourceItems as $key => $sourceItem) {              // n iterations
    foreach ($storedSourceItems as $storedSourceItem) {       // m iterations
        if ($sourceItem->getSku() === $storedSourceItem['sku'] &&
            $sourceItem->getSourceCode() === $storedSourceItem['source_code']) {
            unset($sourceItems[$key]);
            $exisingSourceItems[$storedSourceItem['source_item_id']] = $sourceItem;
        }
     }
 }

Key issues:

  • No early exit — after finding a match, the inner loop continues iterating through all remaining rows (no break).
  • O(n × m) — for 10,000 items where all exist in the DB, that's 100 million comparisons.
  • Each comparison invokes PHP object methods (getSku(), getSourceCode()) rather than plain array access, adding overhead on top of the raw iteration count.

Benchmark:

A real-world benchmark with ~10,000 items (all existing in the database) showed the nested loop taking 289.25 seconds to complete. At this scale the method is a clear bottleneck.

Suggested fix:

I am going to create a PR and replace the nested loop with a hash-map lookup. Index the stored rows by a composite key (source_code + sku) into a 2D array, then iterate over the input items and do O(1) lookups.
This reduces the overall complexity from O(n × m) to O(n + m) and is a straightforward algorithmic improvement with no behavioral changes.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions