Skip to content

Commit 76ff0cf

Browse files
stephen-shelbymergify[bot]
authored andcommitted
[Enhancement] Add enable_optimizer_rule_debug session variable for rule failure diagnosis (#63693)
Signed-off-by: stephen <[email protected]> (cherry picked from commit 6a318c2)
1 parent 3710f1a commit 76ff0cf

File tree

12 files changed

+271
-24
lines changed

12 files changed

+271
-24
lines changed

fe/fe-core/src/main/java/com/starrocks/qe/SessionVariable.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ public static MaterializedViewRewriteMode parse(String str) {
755755

756756
public static final String ENABLE_PLAN_VALIDATION = "enable_plan_validation";
757757

758+
public static final String ENABLE_OPTIMIZER_RULE_DEBUG = "enable_optimizer_rule_debug";
759+
758760
public static final String ENABLE_STRICT_TYPE = "enable_strict_type";
759761

760762
public static final String PARTIAL_UPDATE_MODE = "partial_update_mode";
@@ -2332,6 +2334,9 @@ public long getConnectorSinkTargetMaxFileSize() {
23322334
@VarAttr(name = ENABLE_PLAN_VALIDATION, flag = VariableMgr.INVISIBLE)
23332335
private boolean enablePlanValidation = true;
23342336

2337+
@VarAttr(name = ENABLE_OPTIMIZER_RULE_DEBUG)
2338+
private boolean enableOptimizerRuleDebug = false;
2339+
23352340
@VarAttr(name = SCAN_OR_TO_UNION_LIMIT, flag = VariableMgr.INVISIBLE)
23362341
private int scanOrToUnionLimit = 4;
23372342

@@ -4570,6 +4575,14 @@ public void setEnablePlanValidation(boolean val) {
45704575
this.enablePlanValidation = val;
45714576
}
45724577

4578+
public boolean enableOptimizerRuleDebug() {
4579+
return this.enableOptimizerRuleDebug;
4580+
}
4581+
4582+
public void setEnableOptimizerRuleDebug(boolean enableOptimizerRuleDebug) {
4583+
this.enableOptimizerRuleDebug = enableOptimizerRuleDebug;
4584+
}
4585+
45734586
public boolean isCboPruneSubfield() {
45744587
return cboPruneSubfield;
45754588
}

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/QueryOptimizer.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@
124124
import com.starrocks.sql.optimizer.task.TaskScheduler;
125125
import com.starrocks.sql.optimizer.validate.MVRewriteValidator;
126126
import com.starrocks.sql.optimizer.validate.OptExpressionValidator;
127-
import com.starrocks.sql.optimizer.validate.PlanValidator;
128127
import org.apache.commons.collections4.CollectionUtils;
129128
import org.apache.logging.log4j.LogManager;
130129
import org.apache.logging.log4j.Logger;
@@ -303,8 +302,9 @@ private OptExpression optimizeByCost(ConnectContext connectContext,
303302
mvScan.stream().map(scan -> ((MaterializedView) scan.getTable()).getDbId()).forEach(currentSqlDbIds::add);
304303

305304
try (Timer ignored = Tracers.watchScope("PlanValidate")) {
305+
rootTaskContext.getPlanValidator().enableAllCheckers();
306306
// valid the final plan
307-
PlanValidator.getInstance().validatePlan(finalPlan, rootTaskContext);
307+
rootTaskContext.getPlanValidator().validatePlan(finalPlan, rootTaskContext);
308308
// validate mv and log tracer if needed
309309
MVRewriteValidator mvRewriteValidator = new MVRewriteValidator(allLogicalOlapScanOperators);
310310
mvRewriteValidator.validateMV(connectContext, finalPlan, rootTaskContext);
@@ -550,6 +550,9 @@ private OptExpression logicalRuleRewrite(
550550
rootTaskContext.setRequiredColumns(requiredColumns.clone());
551551
scheduler.rewriteOnce(tree, rootTaskContext, RuleSet.PRUNE_COLUMNS_RULES);
552552

553+
// Enable input dependencies checker after column pruning for rule transformation validation
554+
rootTaskContext.getPlanValidator().enableInputDependenciesChecker();
555+
553556
pruneTables(tree, rootTaskContext, requiredColumns);
554557

555558
scheduler.rewriteIterative(tree, rootTaskContext, new PruneEmptyWindowRule());
@@ -625,7 +628,6 @@ private OptExpression logicalRuleRewrite(
625628

626629
scheduler.rewriteDownTop(tree, rootTaskContext, OnPredicateMoveAroundRule.INSTANCE);
627630
scheduler.rewriteIterative(tree, rootTaskContext, RuleSet.PUSH_DOWN_PREDICATE_RULES);
628-
629631
scheduler.rewriteIterative(tree, rootTaskContext, new PartitionColumnMinMaxRewriteRule());
630632
scheduler.rewriteOnce(tree, rootTaskContext, RuleSet.PARTITION_PRUNE_RULES);
631633
scheduler.rewriteIterative(tree, rootTaskContext, new RewriteMultiDistinctRule());
@@ -656,10 +658,8 @@ private OptExpression logicalRuleRewrite(
656658
scheduler.rewriteOnce(tree, rootTaskContext, new PartitionColumnValueOnlyOnScanRule());
657659
// before MergeProjectWithChildRule, after INLINE_CTE and MergeApplyWithTableFunction
658660
scheduler.rewriteIterative(tree, rootTaskContext, RewriteUnnestBitmapRule.getInstance());
659-
660661
// After this rule, we shouldn't generate logical project operator
661662
scheduler.rewriteIterative(tree, rootTaskContext, new MergeProjectWithChildRule());
662-
663663
scheduler.rewriteOnce(tree, rootTaskContext, new EliminateSortColumnWithEqualityPredicateRule());
664664
scheduler.rewriteOnce(tree, rootTaskContext, new PushDownTopNBelowOuterJoinRule());
665665
// intersect rewrite depend on statistics
@@ -675,7 +675,6 @@ private OptExpression logicalRuleRewrite(
675675

676676
// this rewrite rule should be after mv.
677677
scheduler.rewriteOnce(tree, rootTaskContext, RewriteSimpleAggToHDFSScanRule.SCAN_NO_PROJECT);
678-
679678
// NOTE: This rule should be after MV Rewrite because MV Rewrite cannot handle
680679
// select count(distinct c) from t group by a, b
681680
// if this rule has applied before MV.
@@ -905,7 +904,6 @@ void memoOptimize(ConnectContext connectContext, Memo memo, TaskContext rootTask
905904
private OptExpression physicalRuleRewrite(ConnectContext connectContext, TaskContext rootTaskContext,
906905
OptExpression result) {
907906
Preconditions.checkState(result.getOp().isPhysical());
908-
909907
int planCount = result.getPlanCount();
910908

911909
// Since there may be many different plans in the logic phase, it's possible

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/RowOutputInfo.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public List<ColumnOutputInfo> getCommonColInfo() {
137137
}
138138

139139
public List<ColumnRefOperator> getOutputColRefs() {
140-
return chooseOutputMap().values().stream().map(e -> e.getColumnRef()).collect(Collectors.toList());
140+
return chooseOutputMap().values().stream().map(ColumnOutputInfo::getColumnRef).collect(Collectors.toList());
141141
}
142142

143143
public Map<ColumnRefOperator, ScalarOperator> getColumnRefMap() {

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/base/ColumnRefSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public ColumnRefSet(Collection<ColumnRefOperator> refs) {
4747

4848
public static ColumnRefSet createByIds(Collection<Integer> colIds) {
4949
ColumnRefSet columnRefSet = new ColumnRefSet();
50-
colIds.stream().forEach(columnRefSet::union);
50+
colIds.forEach(columnRefSet::union);
5151
return columnRefSet;
5252
}
5353

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/rule/transformation/PushDownAggregateGroupingSetsRule.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ private OptExpression buildSelectConsume(ColumnRefFactory factory,
247247
/*
248248
* select a, b, c, d, null, sum(x) x from t group by rollup(a, b, c, d)
249249
*/
250-
private OptExpression buildSubRepeatConsume(ColumnRefFactory factory,
250+
public OptExpression buildSubRepeatConsume(ColumnRefFactory factory,
251251
Map<ColumnRefOperator, ColumnRefOperator> outputs,
252252
LogicalAggregationOperator aggregate, LogicalRepeatOperator repeat,
253253
int cteId) {
@@ -357,4 +357,4 @@ private OptExpression buildSubRepeatConsume(ColumnRefFactory factory,
357357
return OptExpression.create(projectOperator,
358358
OptExpression.create(newAggregate, OptExpression.create(newRepeat, OptExpression.create(consume))));
359359
}
360-
}
360+
}

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/task/ApplyRuleTask.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public void execute() {
8989
}
9090
List<OptExpression> targetExpressions;
9191
OptimizerTraceUtil.logApplyRuleBefore(context.getOptimizerContext(), rule, extractExpr);
92+
9293
try (Timer ignore = Tracers.watchScope(Tracers.Module.OPTIMIZER, rule.getClass().getSimpleName())) {
9394
targetExpressions = rule.transform(extractExpr, context.getOptimizerContext());
9495
} catch (StarRocksPlannerException e) {

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/task/RewriteTreeTask.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.starrocks.sql.optimizer.operator.OperatorType;
2424
import com.starrocks.sql.optimizer.operator.pattern.Pattern;
2525
import com.starrocks.sql.optimizer.rule.Rule;
26+
import com.starrocks.sql.optimizer.validate.PlanValidator;
2627

2728
import java.util.List;
2829

@@ -62,8 +63,22 @@ public void execute() {
6263
.getOptimizerOptions().isRuleDisable(rule.type()))) {
6364
return;
6465
}
66+
67+
// Save whole tree state before rule group execution for validation
68+
OptExpression wholePlanBefore = null;
69+
if (context.getOptimizerContext().getSessionVariable().enableOptimizerRuleDebug()) {
70+
wholePlanBefore = planTree.getInputs().get(0);
71+
}
72+
6573
// first node must be RewriteAnchorNode
6674
rewrite(planTree, 0, planTree.getInputs().get(0));
75+
76+
// Validate after the entire rule group execution
77+
if (wholePlanBefore != null && change > 0) {
78+
OptExpression wholePlanAfter = planTree.getInputs().get(0);
79+
PlanValidator.validateAfterRule(wholePlanBefore, wholePlanAfter, rules.get(0), context);
80+
}
81+
6782
// pushdownNotNullPredicates should task-bind, reset it before another RewriteTreeTask
6883
// TODO: refactor TaskContext to make it local to support this requirement better?
6984
context.getOptimizerContext().clearNotNullPredicates();
@@ -97,6 +112,7 @@ protected OptExpression applyRules(OptExpression parent, int childIndex, OptExpr
97112
}
98113

99114
OptimizerTraceUtil.logApplyRuleBefore(context.getOptimizerContext(), rule, root);
115+
100116
List<OptExpression> result;
101117
try (Timer ignore = Tracers.watchScope(Tracers.Module.OPTIMIZER, rule.toString())) {
102118
result = rule.transform(root, context.getOptimizerContext());

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/task/TaskContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import com.starrocks.sql.optimizer.OptimizerContext;
1919
import com.starrocks.sql.optimizer.base.ColumnRefSet;
2020
import com.starrocks.sql.optimizer.base.PhysicalPropertySet;
21+
import com.starrocks.sql.optimizer.validate.PlanValidator;
2122

2223
// The context for optimizer task
2324
public class TaskContext {
2425
private final OptimizerContext optimizerContext;
2526
private final PhysicalPropertySet requiredProperty;
2627
private ColumnRefSet requiredColumns;
2728
private double upperBoundCost;
29+
private final PlanValidator planValidator;
2830

2931
public TaskContext(OptimizerContext context,
3032
PhysicalPropertySet physicalPropertySet,
@@ -34,6 +36,11 @@ public TaskContext(OptimizerContext context,
3436
this.requiredProperty = physicalPropertySet;
3537
this.requiredColumns = requiredColumns;
3638
this.upperBoundCost = cost;
39+
this.planValidator = new PlanValidator();
40+
}
41+
42+
public PlanValidator getPlanValidator() {
43+
return planValidator;
3744
}
3845

3946
public OptimizerContext getOptimizerContext() {

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/validate/CTEUniqueChecker.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public static CTEUniqueChecker getInstance() {
4343
return INSTANCE;
4444
}
4545

46-
4746
@Override
4847
public void validate(OptExpression physicalPlan, TaskContext taskContext) {
4948
CTEUniqueChecker.Visitor visitor = new CTEUniqueChecker.Visitor();

fe/fe-core/src/main/java/com/starrocks/sql/optimizer/validate/InputDependenciesChecker.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,15 @@ private void checkInputCols(ColumnRefSet inputCols, ColumnRefSet usedCols, OptEx
202202
ColumnRefSet missedCols = usedCols.clone();
203203
missedCols.except(inputCols);
204204
if (!missedCols.isEmpty()) {
205-
String message = String.format("Invalid plan:%s%s%s The required cols %s cannot obtain from input cols %s.",
205+
String message = String.format("Invalid plan:%s%s\n%s \nThe required cols %s cannot obtain from input cols %s.",
206206
System.lineSeparator(), optExpr.debugString(), PREFIX, missedCols, inputCols);
207207
throw new StarRocksPlannerException(message, ErrorType.INTERNAL_ERROR);
208208
}
209209
}
210210

211211
private void checkInputType(ColumnRefOperator inputCol, ColumnRefOperator outputCol, OptExpression optExpression) {
212212
if (!outputCol.getType().isFullyCompatible(inputCol.getType())) {
213-
String message = String.format("Invalid plan:%s%s%s Type of output col %s is not fully compatible with " +
213+
String message = String.format("Invalid plan:%s%s\n%s \nType of output col %s is not fully compatible with " +
214214
"type of input col %s.",
215215
System.lineSeparator(), optExpression.debugString(), PREFIX, outputCol, inputCol);
216216
throw new StarRocksPlannerException(message, ErrorType.INTERNAL_ERROR);
@@ -219,7 +219,7 @@ private void checkInputType(ColumnRefOperator inputCol, ColumnRefOperator output
219219

220220
private void checkChildNumberOfSet(int inputSize, int requiredSize, OptExpression optExpression) {
221221
if (inputSize != requiredSize) {
222-
String message = String.format("Invalid plan:%s%s%s. The required number of children is %d but found %d.",
222+
String message = String.format("Invalid plan:%s%s\n%s. \nThe required number of children is %d but found %d.",
223223
System.lineSeparator(), optExpression.debugString(), PREFIX, requiredSize, inputSize);
224224
throw new StarRocksPlannerException(message, ErrorType.INTERNAL_ERROR);
225225
}

0 commit comments

Comments
 (0)