Skip to content
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

[BugFix] Do not apply cardinality-preserving join pruning if there is no prunable joins (backport #50197) #50211

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,44 @@ private void prepare(ConnectContext connectContext, OptExpression logicOperatorT
}
context.setTraceInfo(traceInfo);

<<<<<<< HEAD
if (Config.enable_experimental_mv
&& connectContext.getSessionVariable().isEnableMaterializedViewRewrite()
&& !optimizerConfig.isRuleBased()) {
try (PlannerProfile.ScopedTimer ignored = PlannerProfile.getScopedTimer("Optimizer.preprocessMvs")) {
MvRewritePreprocessor preprocessor =
new MvRewritePreprocessor(connectContext, columnRefFactory, context, logicOperatorTree);
preprocessor.prepareMvCandidatesForPlan();
=======
private void pruneTables(OptExpression tree, TaskContext rootTaskContext, ColumnRefSet requiredColumns) {
if (rootTaskContext.getOptimizerContext().getSessionVariable().isEnableRboTablePrune()) {
if (!Utils.hasPrunableJoin(tree)) {
return;
}
// PARTITION_PRUNE is required to run before ReorderJoinRule because ReorderJoinRule's
// Statistics calculation on Operators depends on row count yielded by the PARTITION_PRUNE.
ruleRewriteOnlyOnce(tree, rootTaskContext, RuleSetType.PARTITION_PRUNE);
// ReorderJoinRule is a in-memo rule, when it is used outside memo, we must apply
// MergeProjectWithChildRule to merge LogicalProjectionOperator into its child's
// projection before ReorderJoinRule's application, after that, we must separate operator's
// projection as LogicalProjectionOperator from the operator by applying SeparateProjectRule.
ruleRewriteIterative(tree, rootTaskContext, new MergeTwoProjectRule());
ruleRewriteIterative(tree, rootTaskContext, new MergeProjectWithChildRule());
CTEUtils.collectForceCteStatisticsOutsideMemo(tree, context);
tree = new UniquenessBasedTablePruneRule().rewrite(tree, rootTaskContext);
deriveLogicalProperty(tree);
tree = new ReorderJoinRule().rewrite(tree, context);
tree = new SeparateProjectRule().rewrite(tree, rootTaskContext);
deriveLogicalProperty(tree);
// TODO(by satanson): bucket shuffle join interpolation in PK table's update query can adjust layout
// of the data ingested by OlapTableSink and eliminate race introduced by multiple concurrent write
// operations on the same tablets, pruning this bucket shuffle join make update statement performance
// regression, so we can turn on this rule after we put an bucket-shuffle exchange in front of
// OlapTableSink in future, at present we turn off this rule.
if (rootTaskContext.getOptimizerContext().getSessionVariable().isEnableTablePruneOnUpdate()) {
tree = new PrimaryKeyUpdateTableRule().rewrite(tree, rootTaskContext);
deriveLogicalProperty(tree);
>>>>>>> 19c38a86d5 ([BugFix] Do not apply cardinality-preserving join pruning if there is no prunable joins (#50197))
}
}
}
Expand Down
42 changes: 42 additions & 0 deletions fe/fe-core/src/main/java/com/starrocks/sql/optimizer/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,48 @@ private static boolean isSuitableJoin(Operator operator, Set<JoinOperator> joinT
return false;
}

<<<<<<< HEAD
=======
public static boolean capableOuterReorder(OptExpression root, int threshold) {
boolean[] hasOuterOrSemi = {false};
int totalJoinNodes = countJoinNode(root, hasOuterOrSemi);
return totalJoinNodes < threshold && hasOuterOrSemi[0];
}

private static int countJoinNode(OptExpression root, boolean[] hasOuterOrSemi) {
int count = 0;
Operator operator = root.getOp();
for (OptExpression child : root.getInputs()) {
if (operator instanceof LogicalJoinOperator && ((LogicalJoinOperator) operator).getJoinHint().isEmpty()) {
count += countJoinNode(child, hasOuterOrSemi);
} else {
count = Math.max(count, countJoinNode(child, hasOuterOrSemi));
}
}

if (operator instanceof LogicalJoinOperator && ((LogicalJoinOperator) operator).getJoinHint().isEmpty()) {
count += 1;
if (!hasOuterOrSemi[0]) {
LogicalJoinOperator joinOperator = (LogicalJoinOperator) operator;
if (joinOperator.getJoinType().isOuterJoin() || joinOperator.getJoinType().isSemiAntiJoin()) {
hasOuterOrSemi[0] = true;
}
}
}
return count;
}

public static boolean hasPrunableJoin(OptExpression expression) {
if (expression.getOp() instanceof LogicalJoinOperator) {
LogicalJoinOperator joinOp = expression.getOp().cast();
JoinOperator joinType = joinOp.getJoinType();
return joinType.isInnerJoin() || joinType.isCrossJoin() ||
joinType.isLeftOuterJoin() || joinType.isRightOuterJoin();
}
return expression.getInputs().stream().anyMatch(Utils::hasPrunableJoin);
}

>>>>>>> 19c38a86d5 ([BugFix] Do not apply cardinality-preserving join pruning if there is no prunable joins (#50197))
public static boolean hasUnknownColumnsStats(OptExpression root) {
Operator operator = root.getOp();
if (operator instanceof LogicalScanOperator) {
Expand Down
Loading
Loading