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

planner: revise the optimize trace output #30882

Merged
merged 8 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from 6 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
70 changes: 35 additions & 35 deletions planner/core/logical_plan_trace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has multiple needed partitions[p1,p2] after pruning",
assertAction: "Datasource[1] becomes PartitionUnion[6] with children[TableScan[1],TableScan[1]]",
assertReason: "DataSource_1 has multiple needed partitions[p1,p2] after pruning",
assertAction: "DataSource_1 becomes PartitionUnion_6 with children[TableScan_1,TableScan_1]",
},
},
},
Expand All @@ -149,8 +149,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has one needed partition[p1] after pruning",
assertAction: "Datasource[1] becomes TableScan[1]",
assertReason: "DataSource_1 has one needed partition[p1] after pruning",
assertAction: "DataSource_1 becomes TableScan_1",
},
},
},
Expand All @@ -160,8 +160,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has multiple needed partitions[p1,p2] after pruning",
assertAction: "Datasource[1] becomes PartitionUnion[7] with children[TableScan[1],TableScan[1]]",
assertReason: "DataSource_1 has multiple needed partitions[p1,p2] after pruning",
assertAction: "DataSource_1 becomes PartitionUnion_7 with children[TableScan_1,TableScan_1]",
},
},
},
Expand All @@ -171,8 +171,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has one needed partition[p2] after pruning",
assertAction: "Datasource[1] becomes TableScan[1]",
assertReason: "DataSource_1 has one needed partition[p2] after pruning",
assertAction: "DataSource_1 becomes TableScan_1",
},
},
},
Expand All @@ -182,8 +182,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] doesn't have needed partition table after pruning",
assertAction: "Datasource[1] becomes TableDual[5]",
assertReason: "DataSource_1 doesn't have needed partition table after pruning",
assertAction: "DataSource_1 becomes TableDual_5",
},
},
},
Expand All @@ -193,8 +193,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has multiple needed partitions[p1,p2] after pruning",
assertAction: "Datasource[1] becomes PartitionUnion[7] with children[TableScan[1],TableScan[1]]",
assertReason: "DataSource_1 has multiple needed partitions[p1,p2] after pruning",
assertAction: "DataSource_1 becomes PartitionUnion_7 with children[TableScan_1,TableScan_1]",
},
},
},
Expand All @@ -204,8 +204,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "partition_processor",
assertRuleSteps: []assertTraceStep{
{
assertReason: "Datasource[1] has one needed partition[p1] after pruning",
assertAction: "Datasource[1] becomes TableScan[1]",
assertReason: "DataSource_1 has one needed partition[p1] after pruning",
assertAction: "DataSource_1 becomes TableScan_1",
},
},
},
Expand Down Expand Up @@ -242,7 +242,7 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
},
{
assertReason: "[test.t.a] is a unique key",
assertAction: "aggregation is simplified to a projection",
assertAction: "Aggregation_2 is simplified to a Projection_4",
},
},
},
Expand All @@ -252,8 +252,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "projection_eliminate",
assertRuleSteps: []assertTraceStep{
{
assertAction: "Proj[2] is eliminated, Proj[3]'s expressions changed into[plus(1, plus(1, test.t.a))]",
assertReason: "Proj[3]'s child proj[2] is redundant",
assertAction: "Projection_2 is eliminated, Projection_3's expressions changed into[plus(1, plus(1, test.t.a))]",
assertReason: "Projection_3's child Projection_2 is redundant",
},
},
},
Expand All @@ -263,8 +263,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "aggregation_push_down",
assertRuleSteps: []assertTraceStep{
{
assertAction: "agg[6] pushed down across join[5], and join right path becomes agg[8]",
assertReason: "agg[6]'s functions[count(Column#38)] are decomposable with join",
assertAction: "Aggregation_6 pushed down across Join_5, and Join_5 right path becomes Aggregation_8",
assertReason: "Aggregation_6's functions[count(Column#38)] are decomposable with join",
},
},
},
Expand All @@ -274,16 +274,16 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "aggregation_push_down",
assertRuleSteps: []assertTraceStep{
{
assertAction: "agg[8] pushed down, and union[5]'s children changed into[[id:11,tp:Aggregation],[id:12,tp:Aggregation]]",
assertReason: "agg[8] functions[sum(Column#28)] are decomposable with union",
assertAction: "Aggregation_8 pushed down, and Union_5's children changed into[Aggregation_11,Aggregation_12]",
assertReason: "Aggregation_8 functions[sum(Column#28)] are decomposable with Union_5",
},
{
assertAction: "proj[6] is eliminated, and agg[11]'s functions changed into[sum(test.t.c),firstrow(test.t.d)]",
assertReason: "Proj[6] is directly below an agg[11] and has no side effects",
assertAction: "Projection_6 is eliminated, and Aggregation_11's functions changed into[sum(test.t.c),firstrow(test.t.d)]",
assertReason: "Projection_6 is directly below an Aggregation_11 and has no side effects",
},
{
assertAction: "proj[7] is eliminated, and agg[12]'s functions changed into[sum(test.t.a),firstrow(test.t.b)]",
assertReason: "Proj[7] is directly below an agg[12] and has no side effects",
assertAction: "Projection_7 is eliminated, and Aggregation_12's functions changed into[sum(test.t.a),firstrow(test.t.b)]",
assertReason: "Projection_7 is directly below an Aggregation_12 and has no side effects",
},
},
},
Expand All @@ -293,16 +293,16 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "max_min_eliminate",
assertRuleSteps: []assertTraceStep{
{
assertAction: "add sort[8],add limit[9] during eliminating agg[4] max function",
assertReason: "agg[4] has only one function[max] without group by, the columns in agg[4] should be sorted",
assertAction: "add Sort_8,add Limit_9 during eliminating Aggregation_4 max function",
assertReason: "Aggregation_4 has only one function[max] without group by, the columns in Aggregation_4 should be sorted",
},
{
assertAction: "add sort[10],add limit[11] during eliminating agg[6] min function",
assertReason: "agg[6] has only one function[min] without group by, the columns in agg[6] should be sorted",
assertAction: "add Sort_10,add Limit_11 during eliminating Aggregation_6 min function",
assertReason: "Aggregation_6 has only one function[min] without group by, the columns in Aggregation_6 should be sorted",
},
{
assertAction: "agg[2] splited into aggs[4,6], and add joins[12] to connect them during eliminating agg[2] multi min/max functions",
assertReason: "each column is sorted and can benefit from index/primary key in agg[4,6] and none of them has group by clause",
assertAction: "Aggregation_2 splited into [Aggregation_4,Aggregation_6], and add [Join_12] to connect them during eliminating Aggregation_2 multi min/max functions",
assertReason: "each column is sorted and can benefit from index/primary key in [Aggregation_4,Aggregation_6] and none of them has group by clause",
},
},
},
Expand All @@ -312,8 +312,8 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "max_min_eliminate",
assertRuleSteps: []assertTraceStep{
{
assertAction: "add selection[4],add sort[5],add limit[6] during eliminating agg[2] max function",
assertReason: "agg[2] has only one function[max] without group by, the columns in agg[2] shouldn't be NULL and needs NULL to be filtered out, the columns in agg[2] should be sorted",
assertAction: "add Selection_4,add Sort_5,add Limit_6 during eliminating Aggregation_2 max function",
assertReason: "Aggregation_2 has only one function[max] without group by, the columns in Aggregation_2 shouldn't be NULL and needs NULL to be filtered out, the columns in Aggregation_2 should be sorted",
},
},
},
Expand All @@ -323,7 +323,7 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "outer_join_eliminate",
assertRuleSteps: []assertTraceStep{
{
assertAction: "Outer join[3] is eliminated and become DataSource[1]",
assertAction: "Outer Join_3 is eliminated and become DataSource_1",
assertReason: "The columns[test.t.b,test.t.c] are from outer table, and the inner join keys[test.t.a] are unique",
},
},
Expand All @@ -334,7 +334,7 @@ func (s *testPlanSuite) TestSingleRuleTraceStep(c *C) {
assertRuleName: "outer_join_eliminate",
assertRuleSteps: []assertTraceStep{
{
assertAction: "Outer join[3] is eliminated and become DataSource[1]",
assertAction: "Outer Join_3 is eliminated and become DataSource_1",
assertReason: "The columns[test.t.a,test.t.b] in agg are from outer table, and the agg functions are duplicate agnostic",
},
},
Expand Down
8 changes: 4 additions & 4 deletions planner/core/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,21 @@ func (op *logicalOptimizeOp) appendBeforeRuleOptimize(index int, name string, be
if op.tracer == nil {
return
}
op.tracer.AppendRuleTracerBeforeRuleOptimize(index, name, before.buildLogicalPlanTrace(before))
op.tracer.AppendRuleTracerBeforeRuleOptimize(index, name, before.buildLogicalPlanTrace())
}

func (op *logicalOptimizeOp) appendStepToCurrent(id int, tp, reason, action string) {
func (op *logicalOptimizeOp) appendStepToCurrent(id int, tp string, reason, action func() string) {
if op.tracer == nil {
return
}
op.tracer.AppendRuleTracerStepToCurrent(id, tp, reason, action)
op.tracer.AppendRuleTracerStepToCurrent(id, tp, reason(), action())
}

func (op *logicalOptimizeOp) recordFinalLogicalPlan(final LogicalPlan) {
if op.tracer == nil {
return
}
op.tracer.RecordFinalLogicalPlan(final.buildLogicalPlanTrace(final))
op.tracer.RecordFinalLogicalPlan(final.buildLogicalPlanTrace())
}

// logicalOptRule means a logical optimizing rule, which contains decorrelate, ppd, column pruning, etc.
Expand Down
8 changes: 4 additions & 4 deletions planner/core/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ type LogicalPlan interface {
canPushToCop(store kv.StoreType) bool

// buildLogicalPlanTrace clone necessary information from LogicalPlan
buildLogicalPlanTrace(p Plan) *tracing.LogicalPlanTrace
buildLogicalPlanTrace() *tracing.LogicalPlanTrace
}

// PhysicalPlan is a tree of the physical operators.
Expand Down Expand Up @@ -382,10 +382,10 @@ func (p *baseLogicalPlan) ExplainInfo() string {
}

// buildLogicalPlanTrace implements LogicalPlan
func (p *baseLogicalPlan) buildLogicalPlanTrace(plan Plan) *tracing.LogicalPlanTrace {
planTrace := &tracing.LogicalPlanTrace{ID: p.ID(), TP: p.TP(), ExplainInfo: plan.ExplainInfo()}
func (p *baseLogicalPlan) buildLogicalPlanTrace() *tracing.LogicalPlanTrace {
planTrace := &tracing.LogicalPlanTrace{ID: p.ID(), TP: p.TP(), ExplainInfo: p.self.ExplainInfo()}
for _, child := range p.Children() {
planTrace.Children = append(planTrace.Children, child.buildLogicalPlanTrace(child))
planTrace.Children = append(planTrace.Children, child.buildLogicalPlanTrace())
}
return planTrace
}
Expand Down
25 changes: 17 additions & 8 deletions planner/core/rule_aggregation_elimination.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (a *aggregationEliminateChecker) tryToEliminateAggregation(agg *LogicalAggr
// GroupByCols has unique key, so this aggregation can be removed.
if ok, proj := ConvertAggToProj(agg, agg.schema); ok {
proj.SetChildren(agg.children[0])
appendAggregationEliminateTraceStep(agg, uniqueKey, opt)
appendAggregationEliminateTraceStep(agg, proj, uniqueKey, opt)
return proj
}
}
Expand Down Expand Up @@ -116,17 +116,26 @@ func (a *aggregationEliminateChecker) tryToEliminateDistinct(agg *LogicalAggrega
}
}

func appendAggregationEliminateTraceStep(agg *LogicalAggregation, uniqueKey expression.KeyInfo, opt *logicalOptimizeOp) {
opt.appendStepToCurrent(agg.ID(), agg.TP(),
fmt.Sprintf("%s is a unique key", uniqueKey.String()),
"aggregation is simplified to a projection")
func appendAggregationEliminateTraceStep(agg *LogicalAggregation, proj *LogicalProjection, uniqueKey expression.KeyInfo, opt *logicalOptimizeOp) {
reason := func() string {
return fmt.Sprintf("%s is a unique key", uniqueKey.String())
}
action := func() string {
return fmt.Sprintf("%v_%v is simplified to a %v_%v", agg.TP(), agg.ID(), proj.TP(), proj.ID())
}

opt.appendStepToCurrent(agg.ID(), agg.TP(), reason, action)
}

func appendDistinctEliminateTraceStep(agg *LogicalAggregation, uniqueKey expression.KeyInfo, af *aggregation.AggFuncDesc,
opt *logicalOptimizeOp) {
opt.appendStepToCurrent(agg.ID(), agg.TP(),
fmt.Sprintf("%s is a unique key", uniqueKey.String()),
fmt.Sprintf("%s(distinct ...) is simplified to %s(...)", af.Name, af.Name))
reason := func() string {
return fmt.Sprintf("%s is a unique key", uniqueKey.String())
}
action := func() string {
return fmt.Sprintf("%s(distinct ...) is simplified to %s(...)", af.Name, af.Name)
}
opt.appendStepToCurrent(agg.ID(), agg.TP(), reason, action)
}

// ConvertAggToProj convert aggregation to projection.
Expand Down
32 changes: 17 additions & 15 deletions planner/core/rule_aggregation_push_down.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ func (*aggregationPushDownSolver) name() string {
func appendAggPushDownAcrossJoinTraceStep(oldAgg, newAgg *LogicalAggregation, aggFuncs []*aggregation.AggFuncDesc, join *LogicalJoin,
childIdx int, opt *logicalOptimizeOp) {
reason := func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v]'s functions[", oldAgg.ID()))
buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v's functions[", oldAgg.TP(), oldAgg.ID()))
for i, aggFunc := range aggFuncs {
if i > 0 {
buffer.WriteString(",")
Expand All @@ -526,23 +526,23 @@ func appendAggPushDownAcrossJoinTraceStep(oldAgg, newAgg *LogicalAggregation, ag
}
buffer.WriteString("] are decomposable with join")
return buffer.String()
}()
}
action := func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v] pushed down across join[%v], ", oldAgg.ID(), join.ID()))
buffer.WriteString(fmt.Sprintf("and join %v path becomes agg[%v]", func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v pushed down across %v_%v, ", oldAgg.TP(), oldAgg.ID(), join.TP(), join.ID()))
buffer.WriteString(fmt.Sprintf("and %v_%v %v path becomes %v_%v", join.TP(), join.ID(), func() string {
if childIdx == 0 {
return "left"
}
return "right"
}(), newAgg.ID()))
}(), newAgg.TP(), newAgg.ID()))
return buffer.String()
}()
}
opt.appendStepToCurrent(join.ID(), join.TP(), reason, action)
}

func appendAggPushDownAcrossProjTraceStep(agg *LogicalAggregation, proj *LogicalProjection, opt *logicalOptimizeOp) {
action := func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("proj[%v] is eliminated, and agg[%v]'s functions changed into[", proj.ID(), agg.ID()))
buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v is eliminated, and %v_%v's functions changed into[", proj.TP(), proj.ID(), agg.TP(), agg.ID()))
for i, aggFunc := range agg.AggFuncs {
if i > 0 {
buffer.WriteString(",")
Expand All @@ -551,33 +551,35 @@ func appendAggPushDownAcrossProjTraceStep(agg *LogicalAggregation, proj *Logical
}
buffer.WriteString("]")
return buffer.String()
}()
reason := fmt.Sprintf("Proj[%v] is directly below an agg[%v] and has no side effects", proj.ID(), agg.ID())
}
reason := func() string {
return fmt.Sprintf("%v_%v is directly below an %v_%v and has no side effects", proj.TP(), proj.ID(), agg.TP(), agg.ID())
}
opt.appendStepToCurrent(agg.ID(), agg.TP(), reason, action)
}

func appendAggPushDownAcrossUnionTraceStep(union *LogicalUnionAll, agg *LogicalAggregation, opt *logicalOptimizeOp) {
reason := func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v] functions[", agg.ID()))
buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v functions[", agg.TP(), agg.ID()))
for i, aggFunc := range agg.AggFuncs {
if i > 0 {
buffer.WriteString(",")
}
buffer.WriteString(aggFunc.String())
}
buffer.WriteString("] are decomposable with union")
buffer.WriteString(fmt.Sprintf("] are decomposable with %v_%v", union.TP(), union.ID()))
return buffer.String()
}()
}
action := func() string {
buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v] pushed down, and union[%v]'s children changed into[", agg.ID(), union.ID()))
buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v pushed down, and %v_%v's children changed into[", agg.TP(), agg.ID(), union.TP(), union.ID()))
for i, child := range union.Children() {
if i > 0 {
buffer.WriteString(",")
}
buffer.WriteString(fmt.Sprintf("[id:%v,tp:%s]", child.ID(), child.TP()))
buffer.WriteString(fmt.Sprintf("%v_%v", child.TP(), child.ID()))
}
buffer.WriteString("]")
return buffer.String()
}()
}
opt.appendStepToCurrent(union.ID(), union.TP(), reason, action)
}
16 changes: 11 additions & 5 deletions planner/core/rule_eliminate_projection.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func (*projectionEliminator) name() string {
func appendDupProjEliminateTraceStep(parent, child *LogicalProjection, opt *logicalOptimizeOp) {
action := func() string {
buffer := bytes.NewBufferString(
fmt.Sprintf("Proj[%v] is eliminated, Proj[%v]'s expressions changed into[", child.ID(), parent.ID()))
fmt.Sprintf("%v_%v is eliminated, %v_%v's expressions changed into[", child.TP(), child.ID(), parent.TP(), parent.ID()))
for i, expr := range parent.Exprs {
if i > 0 {
buffer.WriteString(",")
Expand All @@ -309,13 +309,19 @@ func appendDupProjEliminateTraceStep(parent, child *LogicalProjection, opt *logi
}
buffer.WriteString("]")
return buffer.String()
}()
reason := fmt.Sprintf("Proj[%v]'s child proj[%v] is redundant", parent.ID(), child.ID())
}
reason := func() string {
return fmt.Sprintf("%v_%v's child %v_%v is redundant", parent.TP(), parent.ID(), child.TP(), child.ID())
}
opt.appendStepToCurrent(child.ID(), child.TP(), reason, action)
}

func appendProjEliminateTraceStep(proj *LogicalProjection, opt *logicalOptimizeOp) {
reason := fmt.Sprintf("Proj[%v]'s Exprs are all Columns", proj.ID())
action := fmt.Sprintf("Proj[%v] is eliminated", proj.ID())
reason := func() string {
return fmt.Sprintf("%v_%v's Exprs are all Columns", proj.TP(), proj.ID())
}
action := func() string {
return fmt.Sprintf("%v_%v is eliminated", proj.TP(), proj.ID())
}
opt.appendStepToCurrent(proj.ID(), proj.TP(), reason, action)
}
Loading