Skip to content

Do not extract distinct operator when de-correlating global aggregation#12582

Merged
kasiafi merged 1 commit intotrinodb:masterfrom
kasiafi:359DecorrelationRegression
May 30, 2022
Merged

Do not extract distinct operator when de-correlating global aggregation#12582
kasiafi merged 1 commit intotrinodb:masterfrom
kasiafi:359DecorrelationRegression

Conversation

@kasiafi
Copy link
Copy Markdown
Member

@kasiafi kasiafi commented May 27, 2022

Fixes: #12564

Credits to @sopel39 for investigating this complicated case.

Before this change, rules
TestTransformCorrelatedGlobalAggregationWithoutProjection and
TestTransformCorrelatedGlobalAggregationWithProjection extracted
and handled two aggregations in the correlated subquery:

  • a global aggregation
  • a "distinct operator" - i.e. an aggregation with grouping symbols
    but without any aggregate functions

It is a common case that such two aggregations are present. They
result from a call like: count(distinct x)

Before this change, if both aggregations were present in the subquery,
the rules would move them both on top of the de-correlated join.
This behavior was suboptimal in some cases, specifically when the
"distinct operator" could be de-correlated in place. Moving the
"distinct operator" on top of the join blocked other optimizations,
e.g. PushAggregationThroughOuterJoin.

After this change, the "distinct operator" is moved on top of the
de-correlated join only if it can't be de-correlated in the
subquery.

This change might need a release notes entry as a perf improvement / regression fix.

@cla-bot cla-bot bot added the cla-signed label May 27, 2022
@kasiafi kasiafi requested a review from sopel39 May 27, 2022 20:09
@findepi
Copy link
Copy Markdown
Member

findepi commented May 28, 2022

Addresses: #12564

"Fixes" ?

@kasiafi
Copy link
Copy Markdown
Member Author

kasiafi commented May 28, 2022

"Fixes" ?

Not sure. The plan still differs in some aspects from the expected plan described in the issue. I think this solution is good, but we could investigate further.

@kasiafi kasiafi force-pushed the 359DecorrelationRegression branch 3 times, most recently from 5e48662 to b18b8de Compare May 28, 2022 07:20
Before this change, rules
`TestTransformCorrelatedGlobalAggregationWithoutProjection` and
`TestTransformCorrelatedGlobalAggregationWithProjection` extracted
and handled two aggregations in the correlated subquery:
- a global aggregation
- a "distinct operator" - i.e. an aggregation with grouping symbols
  but without any aggregate functions
It is a common case that such two aggregations are present. They
result from a call like: `count(distinct x)`

Before this change, if both aggregations were present in the subquery,
the rules would move them both on top of the de-correlated join.
This behavior was suboptimal in some cases, specifically when the
"distinct operator" could be de-correlated in place. Moving the
"distinct operator" on top of the join blocked other optimizations,
e.g. `PushAggregationThroughOuterJoin`.

After this change, the "distinct operator" is moved on top of the
de-correlated join only if it can't be de-correlated in the
subquery.
@Test
public void testCorrelatedDistinctAggregationRewriteToLeftOuterJoin()
{
assertPlan(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this is testing PushAggregationThroughOuterJoin?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It checks the de-correlation rule TransformCorrelatedGlobalAggregationWithoutProjection combined with PushAggregationThroughOuterJoin. Before the change, PushAggregationThroughOuterJoin didn't fire because of misplaced "distinct operator".

@sopel39
Copy link
Copy Markdown
Member

sopel39 commented May 30, 2022

Not sure. The plan still differs in some aspects from the expected plan described in the issue. I think this solution is good, but we could investigate further.

wdym?

@kasiafi
Copy link
Copy Markdown
Member Author

kasiafi commented May 30, 2022

Not sure. The plan still differs in some aspects from the expected plan described in the issue. I think this solution is good, but we could investigate further.

wdym?

@sopel39 I checked the EXPLAIN closely. I can see one difference between the plan in version 347, and after this change: after this change, the decorrelated count aggregation has a mask: count("orderkey") (mask = non_null).

The mask was added as a correctness fix, which addresses any aggregations which are "null-sensitive", that is, return different results on empty input than on input consisting of nulls. An example of a "null-sensitive" aggregation is count().

My conclusion is that this PR fixes the issue even though the mask was introduced.

@kasiafi
Copy link
Copy Markdown
Member Author

kasiafi commented May 30, 2022

@sopel39 let me know if you have any more concerns or you think it is ready to go.

@sopel39
Copy link
Copy Markdown
Member

sopel39 commented May 30, 2022

I think it looks good

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

Development

Successfully merging this pull request may close these issues.

Higher memory consumption at COUNT(DISTINCT) in correlated subquery since 348

3 participants