-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Broadcast join if build estimation is small and from HBO #22681
Conversation
@@ -124,6 +128,12 @@ private PlanNode getCostBasedDistributionType(SemiJoinNode node, Context context | |||
possibleJoinNodes.add(getSemiJoinNodeWithCost(node.withDistributionType(PARTITIONED), context)); | |||
|
|||
if (possibleJoinNodes.stream().anyMatch(result -> result.getCost().hasUnknownComponents())) { | |||
if (isUseBroadcastJoinWhenBuildSizeSmallProbeSizeUnknownEnabled(context.getSession()) && possibleJoinNodes.stream().anyMatch(result -> ((SemiJoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED))) { |
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.
Also enable it for semi join
@@ -126,7 +127,10 @@ private PlanNode getCostBasedJoin(JoinNode joinNode, Context context) | |||
if (possibleJoinNodes.stream().anyMatch(result -> result.getCost().hasUnknownComponents()) || possibleJoinNodes.isEmpty()) { | |||
// TODO: currently this session parameter is added so as to roll out the plan change gradually, after proved to be a better choice, make it default and get rid of the session parameter here. | |||
if (isUseBroadcastJoinWhenBuildSizeSmallProbeSizeUnknownEnabled(context.getSession()) && possibleJoinNodes.stream().anyMatch(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED))) { | |||
return getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); | |||
JoinNode broadcastJoin = (JoinNode) getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); |
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.
We should do it always - we trust history and if HBO says build side is small, we just broadcast it.
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.
This depends on whether the other side of the join is small or not, i.e. if both sides have estimations showing data size is small, whether we should do partitioned join or broadcast join. I think we can open a separate PR for this.
This might be a good time to fix and use the correct confidence level in planNodeStatsEstimate I had a PR #21280 since we were facing a similar issue |
But that might involve additional testing and could be an overkill for this case so will leave you to decide |
Suggest revising the release note entry to follow the Order of changes in the Release Notes Guidelines. Maybe something like this? Edit this as needed, please.
|
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.
I have a couple of related questions
-
It is well known that incorrect cost estimates can negatively influence optimizer planning. With this change, if the cost were correct, then we lose the benefit of the optimization - do we not?
-
I agree that the HBO is a better source of truth. I wonder if we should introduce a config parameter (or a set of configs) that govern whether some optimizations should apply based on stats sources? Maintenance becomes hard if we pepper the code-base with hard-coded special cases for HBO optimizations.
@@ -126,7 +127,10 @@ private PlanNode getCostBasedJoin(JoinNode joinNode, Context context) | |||
if (possibleJoinNodes.stream().anyMatch(result -> result.getCost().hasUnknownComponents()) || possibleJoinNodes.isEmpty()) { | |||
// TODO: currently this session parameter is added so as to roll out the plan change gradually, after proved to be a better choice, make it default and get rid of the session parameter here. | |||
if (isUseBroadcastJoinWhenBuildSizeSmallProbeSizeUnknownEnabled(context.getSession()) && possibleJoinNodes.stream().anyMatch(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED))) { | |||
return getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); | |||
JoinNode broadcastJoin = (JoinNode) getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); |
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.
nit: limit lines to 180 chars
Agree that we need to have different confidence level for estimations. I will consider this PR as a simple fix for existing features and not including other major changes. |
Yes, we will. But fail queries which ran successfully is a larger pain than failing to optimize queries already running successful/failing. And this is the reason why we still cannot turn on this feature internally.
I think this is a good idea and not only applicable to this optimization, but also other optimizations. But it also involves larger changes. I think we can open an issue for this. |
return getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); | ||
JoinNode broadcastJoin = (JoinNode) getOnlyElement(possibleJoinNodes.stream().filter(result -> ((JoinNode) result.getPlanNode()).getDistributionType().get().equals(REPLICATED)).map(x -> x.getPlanNode()).collect(toImmutableList())); | ||
if (context.getStatsProvider().getStats(broadcastJoin.getBuild()).getSourceInfo() instanceof HistoryBasedSourceInfo) { | ||
return broadcastJoin; |
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.
I think, in future whether the previous join was broadcast/hash and if it was efficient/or if it failed etc could also be stored using HBO
Description
Previously I added this session property to do broadcast join when build side is small and probe side is unknown. However, in production we found that it will cause problem when the build side estimation is wrong. However, HBO is a confident source and we should be able to enable it when the estimation is from HBO.
Motivation and Context
To improve performance for queries with unknown probe and small build.
Impact
To improve performance for queries with unknown probe and small build.
Test Plan
It's an easy change, and also tested locally end to end.
Contributor checklist
Release Notes
Please follow release notes guidelines and fill in the release notes below.