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.
The
separateExistingAndNewItemsmethod inMagento\Inventory\Model\ResourceModel\SourceItem\SaveMultipleuses 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:
Key issues:
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.