[feature](nereids) explain shape plan (#18296)
`explain shape plan select ...` only print plan shape related information, including - node name - join type, join condition - filter condition - agg phase It is painful to maintain regression cases using explain since there are a lot of mutable information, like slot id. By this pr, we could use explain shape plan in regression cases. for exmaple: this is tpch q2 +-----------------------------------------------------------------------------------------------------------+ | Explain String | +-----------------------------------------------------------------------------------------------------------+ | PhysicalTopN | | --PhysicalDistribute | | ----PhysicalTopN | | ------PhysicalProject | | --------filter((cast(ps_supplycost as DECIMAL(27, 9)) = min(ps_supplycost) OVER(PARTITION BY p_partkey))) | | ----------PhysicalWindow | | ------------PhysicalQuickSort | | --------------PhysicalProject | | ----------------hashJoin[INNER_JOIN](supplier.s_suppkey = partsupp.ps_suppkey) | | ------------------PhysicalProject | | --------------------hashJoin[INNER_JOIN](part.p_partkey = partsupp.ps_partkey) | | ----------------------PhysicalProject | | ------------------------PhysicalOlapScan[partsupp] | | ----------------------PhysicalProject | | ------------------------filter((part.p_size = 15)(p_type like '%BRASS')) | | --------------------------PhysicalOlapScan[part] | | ------------------PhysicalDistribute | | --------------------hashJoin[INNER_JOIN](supplier.s_nationkey = nation.n_nationkey) | | ----------------------PhysicalOlapScan[supplier] | | ----------------------PhysicalDistribute | | ------------------------hashJoin[INNER_JOIN](nation.n_regionkey = region.r_regionkey) | | --------------------------PhysicalProject | | ----------------------------PhysicalOlapScan[nation] | | --------------------------PhysicalDistribute | | ----------------------------PhysicalProject | | ------------------------------filter((region.r_name = 'EUROPE')) | | --------------------------------PhysicalOlapScan[region] | +-----------------------------------------------------------------------------------------------------------+
This commit is contained in:
@ -330,6 +330,7 @@ SESSION_USER: 'SESSION_USER';
|
||||
SET: 'SET';
|
||||
SETMINUS: 'MINUS';
|
||||
SETS: 'SETS';
|
||||
SHAPE: 'SHAPE';
|
||||
SHOW: 'SHOW';
|
||||
SKEWED: 'SKEWED';
|
||||
SOME: 'SOME';
|
||||
|
||||
@ -64,6 +64,7 @@ planType
|
||||
| ANALYZED
|
||||
| REWRITTEN | LOGICAL // same type
|
||||
| OPTIMIZED | PHYSICAL // same type
|
||||
| SHAPE
|
||||
| ALL // default type
|
||||
;
|
||||
|
||||
|
||||
@ -219,7 +219,10 @@ public class NereidsPlanner extends Planner {
|
||||
LOG.info(tree);
|
||||
}
|
||||
|
||||
if (explainLevel == ExplainLevel.OPTIMIZED_PLAN || explainLevel == ExplainLevel.ALL_PLAN) {
|
||||
System.out.println(physicalPlan.shape(" "));
|
||||
if (explainLevel == ExplainLevel.OPTIMIZED_PLAN
|
||||
|| explainLevel == ExplainLevel.ALL_PLAN
|
||||
|| explainLevel == ExplainLevel.SHAPE_PLAN) {
|
||||
optimizedPlan = physicalPlan;
|
||||
}
|
||||
|
||||
@ -354,6 +357,8 @@ public class NereidsPlanner extends Planner {
|
||||
return rewrittenPlan.treeString();
|
||||
case OPTIMIZED_PLAN:
|
||||
return "cost = " + cost + "\n" + optimizedPlan.treeString();
|
||||
case SHAPE_PLAN:
|
||||
return optimizedPlan.shape("");
|
||||
case ALL_PLAN:
|
||||
return "========== PARSED PLAN ==========\n"
|
||||
+ parsedPlan.treeString() + "\n\n"
|
||||
|
||||
@ -55,6 +55,11 @@ public abstract class BinaryOperator extends Expression implements BinaryExpress
|
||||
return "(" + left().toString() + " " + symbol + " " + right().toString() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
return "(" + left().shapeInfo() + " " + symbol + " " + right().shapeInfo() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(symbol, left(), right());
|
||||
|
||||
@ -210,4 +210,8 @@ public abstract class Expression extends AbstractTreeNode<Expression> implements
|
||||
return false;
|
||||
}
|
||||
|
||||
public String shapeInfo() {
|
||||
return toSql();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -124,6 +124,15 @@ public class SlotReference extends Slot {
|
||||
return name + "#" + exprId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
if (qualifier.isEmpty()) {
|
||||
return name;
|
||||
} else {
|
||||
return qualifier.get(qualifier.size() - 1) + "." + name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
||||
@ -145,4 +145,29 @@ public interface Plan extends TreeNode<Plan> {
|
||||
}
|
||||
|
||||
void setMutableState(String key, Object value);
|
||||
|
||||
/**
|
||||
* a simple version of explain, used to verify plan shape
|
||||
* @param prefix " "
|
||||
* @return string format of plan shape
|
||||
*/
|
||||
default String shape(String prefix) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(prefix).append(shapeInfo()).append("\n");
|
||||
String childPrefix = prefix + "--";
|
||||
children().forEach(
|
||||
child -> {
|
||||
builder.append(child.shape(childPrefix));
|
||||
}
|
||||
);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* used in shape()
|
||||
* @return default value is its class name
|
||||
*/
|
||||
default String shapeInfo() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ public class ExplainCommand extends Command implements NoForward {
|
||||
ANALYZED_PLAN(true),
|
||||
REWRITTEN_PLAN(true),
|
||||
OPTIMIZED_PLAN(true),
|
||||
SHAPE_PLAN(true),
|
||||
ALL_PLAN(true)
|
||||
;
|
||||
|
||||
|
||||
@ -54,5 +54,4 @@ public abstract class AbstractPhysicalPlan extends AbstractPlan implements Physi
|
||||
public PhysicalProperties getPhysicalProperties() {
|
||||
return physicalProperties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -123,4 +123,13 @@ public class PhysicalFilter<CHILD_TYPE extends Plan> extends PhysicalUnary<CHILD
|
||||
return new PhysicalFilter<>(conjuncts, groupExpression, getLogicalProperties(), physicalProperties,
|
||||
statistics, child());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("filter(");
|
||||
conjuncts.forEach(conjunct -> builder.append(conjunct.shapeInfo()));
|
||||
builder.append(")");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,4 +272,11 @@ public class PhysicalHashAggregate<CHILD_TYPE extends Plan> extends PhysicalUnar
|
||||
aggregateParam, maybeUsingStream, Optional.empty(), getLogicalProperties(),
|
||||
requireProperties, physicalProperties, statistics, newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
StringBuilder builder = new StringBuilder("hashAgg[");
|
||||
builder.append(getAggPhase()).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,4 +152,17 @@ public class PhysicalHashJoin<
|
||||
return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, hint, markJoinSlotReference,
|
||||
groupExpression, getLogicalProperties(), physicalProperties, statistics, left(), right());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("hashJoin[").append(joinType).append("]");
|
||||
hashJoinConjuncts.forEach(expr -> {
|
||||
builder.append(expr.shapeInfo());
|
||||
});
|
||||
otherJoinConjuncts.forEach(expr -> {
|
||||
builder.append(expr.shapeInfo());
|
||||
});
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,4 +167,12 @@ public class PhysicalNestedLoopJoin<
|
||||
public boolean isBitMapRuntimeFilterConditionsEmpty() {
|
||||
return bitMapRuntimeFilterConditions.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
StringBuilder builder = new StringBuilder("NestedLoopJoin");
|
||||
builder.append("[").append(joinType).append("]");
|
||||
otherJoinConjuncts.forEach(expr -> builder.append(expr.shapeInfo()));
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,4 +155,12 @@ public class PhysicalOlapScan extends PhysicalRelation implements OlapScan {
|
||||
selectedPartitionIds, distributionSpec, preAggStatus, groupExpression,
|
||||
getLogicalProperties(), physicalProperties, statistics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shapeInfo() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(this.getClass().getSimpleName()).append("[").append(olapTable.getName()).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user