Skip to content

#40704: Prevent full table scan in sales order child collections for orders without an id - #41106

Open
lbajsarowicz wants to merge 1 commit into
magento:2.4-developfrom
lbajsarowicz:fix/sales-order-collection-empty-order-filter
Open

#40704: Prevent full table scan in sales order child collections for orders without an id#41106
lbajsarowicz wants to merge 1 commit into
magento:2.4-developfrom
lbajsarowicz:fix/sales-order-collection-empty-order-filter

Conversation

@lbajsarowicz

Copy link
Copy Markdown
Contributor

Description

Magento\Sales\Model\ResourceModel\Order\Collection\AbstractCollection::setOrderFilter() handles an order without an ID by faking the loaded state instead of constraining the select:

} else {
    $this->_totalRecords = 0;
    $this->_setIsLoaded(true);
}

No condition is added to _select, so the select still matches every row of sales_invoice / sales_shipment / sales_creditmemo. As long as nothing touches the loaded state, the collection behaves correctly. But any reset of that state re-opens the unfiltered select:

  • Magento\Framework\Data\Collection::clear() sets _isCollectionLoaded = false and _totalRecords = null
  • Magento\Framework\Data\Collection\AbstractDb::_reset() sets _isCollectionLoaded = false

After either of those, the next load() or getSize() runs against the whole table — a full table scan returning unrelated invoices, shipments or credit memos for an order that has none.

Fixed Issues

Reported by @ln8711 in #40704 (comment) while reviewing #40731.

Related to #40704.

Manual testing scenarios

  1. Have at least one invoice in the database.
  2. Build a collection for an order that has no ID:
$order = $orderFactory->create();
$collection = $invoiceCollectionFactory->create()->setOrderFilter($order);
$collection->clear();
var_dump($collection->getSize(), count($collection->getItems()));

Before: getSize() reports the total number of invoices in the table and getItems() returns them.
After: both report 0, and the emitted SQL carries parent_id = 0.

Questions or comments

The _setIsLoaded(true) shortcut is kept on purpose — it keeps the common "new order, no children yet" path free of any query during order placement. The added filter only guarantees that a reset cannot degrade into a table scan.

Covered by a new integration test in Magento\Sales\Model\ResourceModel\Order\Collection\AbstractCollectionTest.

…rders without id

setOrderFilter() marked the collection as loaded with zero records instead
of adding a condition to the select. Anything that resets the loaded state
afterwards - clear(), _reset() - left the select unfiltered, so the next
load() or getSize() scanned the whole sales_invoice, sales_shipment or
sales_creditmemo table. Add a never-matching condition on the parent id
field as well, so a reset cannot leak into a full table scan.
@m2-assistant

m2-assistant Bot commented Aug 7, 2026

Copy link
Copy Markdown

Hi @lbajsarowicz. Thank you for your contribution!
Here are some useful tips on how you can test your changes using Magento test environment.
❗ Automated tests can be triggered manually with an appropriate comment:

  • @magento run all tests - run or re-run all required tests against the PR changes
  • @magento run <test-build(s)> - run or re-run specific test build(s)
    For example: @magento run Unit Tests

<test-build(s)> is a comma-separated list of build names.

Allowed build names are:
  1. Database Compare
  2. Functional Tests CE
  3. Functional Tests EE
  4. Functional Tests B2B
  5. Integration Tests
  6. Magento Health Index
  7. Sample Data Tests CE
  8. Sample Data Tests EE
  9. Sample Data Tests B2B
  10. Static Tests
  11. Unit Tests
  12. WebAPI Tests
  13. Semantic Version Checker

You can find more information about the builds here
ℹ️ Run only required test builds during development. Run all test builds before sending your pull request for review.


For more details, review the Code Contributions documentation.
Join Magento Community Engineering Slack and ask your questions in #github channel.

@lbajsarowicz

Copy link
Copy Markdown
Contributor Author

@magento run all tests

@engcom-Hotel engcom-Hotel added Triage: Dev.Experience Issue related to Developer Experience and needs help with Triage to Confirm or Reject it Priority: P2 A defect with this priority could have functionality issues which are not to expectations. labels Aug 11, 2026
@github-project-automation github-project-automation Bot moved this to Pending Review in Pull Requests Dashboard Aug 11, 2026
@danielrussob

Copy link
Copy Markdown

@magento run all tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Priority: P2 A defect with this priority could have functionality issues which are not to expectations. Progress: pending review Triage: Dev.Experience Issue related to Developer Experience and needs help with Triage to Confirm or Reject it

Projects

Status: Pending Review

Development

Successfully merging this pull request may close these issues.

3 participants