-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix performance leak in salesrule collection #20484
Fix performance leak in salesrule collection #20484
Conversation
Github Issue: magento#19117 Refactored sql query that created a huge temporary table for each request, when a greater amount of salesrules and coupon codes exists in database. The sorting of this table took a lot of cpu time. The statement now consists of two subselects that drill down the remaining lines as far as possible, so that the remaining temporary table is minimal and easily sorted. example: for 2,000 salesrules and 3,000,000 coupon codes the original query took about 2.4 seconds (mbp, server, aws). the optimized query takes about 5ms (about 100ms on aws).
Hi @david-fuehr. Thank you for your contribution
For more details, please, review the Magento Contributor Assistant documentation |
$couponRules = $this->getCouponCodeSelect($couponCode); | ||
|
||
$allAllowedRules = $this->getConnection()->select(); | ||
$allAllowedRules->union([$noCouponRules, $couponRules], \Zend_Db_Select::SQL_UNION_ALL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you merge sales rules without coupons ($noCouponRules) to select in case, when we filter by specific coupon?
If you will have a big amount of sales rules without a coupon code (coupon_type == Rule::COUPON_TYPE_NO_COUPON) then you will have big performance degradation.
I think we should optimize this flow
BTW, you can experiment with a big amount of sales rules using generation toolkit: https://devdocs.magento.com/guides/v2.3/config-guide/cli/config-cli-subcommands-perf-data.html (you can adjust [car_price_rule](https://github.com/magento/magento2/blob/2.3-develop/setup/performance-toolkit/profiles/ce/small.xml#L40 for generate any amount of sales rules)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this PR you can ignore ^^ my comment, due to it relates to current process how we apply sales rules to the cart. It can be implemented in separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review and your comment. As I understand, it is necessary to return all valid rules when a coupon code is available - even those without a coupon code, because they may be applied automatically (I suppose you referred to that in your second comment).
And you are right - a lot of active salesrules with Rule::COUPON_TYPE_NO_COUPON
will have an impact on the performance. But I would say that a big amount of salesrules is maybe 5,000 rules. When you create five salesrules with a autogenerated coupon for each of your 100,000 newsletter subscribers, you will have 500,000 coupon codes. In my opinion this is the most likely case to massively increase the size of the temporary table in the original statement. The refactoring addresses the latter.
@magento-engcom-team give me test instance |
Hi @larsroettig. Thank you for your request. I'm working on Magento instance for you |
Hi @larsroettig, here is your new Magento instance. |
Hi @larsroettig, thank you for the review. |
@david-fuehr thank you for contributing. Please accept Community Contributors team invitation here to gain extended permissions for this repository. |
✅ Review I we need this fix for one of our customer and it works well |
Hi @david-fuehr can you please update the branch, resolve conflicts and check if the issue is still actual (it may have been fixed considering the conflicting code changes). |
Hi @sivaschenko, thanks for asking. I checked the changes from magento/2.3-develop. They address the issue I was working on. In two details I prefer my solution:
$orWhereConditions = [
"(" . implode($autoGeneratedCouponCondition, " AND ") . ")",
$connection->quoteInto(
'(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)',
\Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
),
$connection->quoteInto(
'(main_table.coupon_type = ? AND main_table.use_auto_generation = 0 AND rule_coupons.type = 0)',
\Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
),
]; vs $isValidSpecific =
$this->getConnection()->quoteInto('(main_table.coupon_type = ?)', Rule::COUPON_TYPE_SPECIFIC)
. ' AND (' .
'(main_table.use_auto_generation = 1 AND rule_coupons.type = 1)'
. ' OR ' .
'(main_table.use_auto_generation = 0 AND rule_coupons.type = 0)'
. ')';
I resolved the conflict, so you could merge this pull request. But I am also totally fine, if you choose to keep the current changes and close this pull request. |
Hi @sivaschenko, thank you for the review. |
Hi @david-fuehr, thank you for your contribution! |
Description
Refactored sql query that created a huge temporary table for each request, when a greater amount of salesrules and coupon codes exists in database. The sorting of this table took a lot of cpu time.
The statement now consists of two subselects that drill down the remaining lines as far as possible, so that the remaining temporary table is minimal and easily sorted.
Fixed Issues
Manual testing scenarios
A
)B
)coupon_type = 'autogenerated'
and generate 5000 codes (C
)coupon_type = 'specific'
(D
)E
)A
C
to the cartA,C
D
to the cartA,D
E
to the cartA
topriority = 1
D
topriority = 2
A
D
A,D
A
topriority = 3
D,A
Additional Information
We use this fix in a magento commerce environment
Contribution checklist