diff --git a/planner/core/logical_plan_trace_test.go b/planner/core/logical_plan_trace_test.go index 0d4577bc1f107..c09ffb1f19b6c 100644 --- a/planner/core/logical_plan_trace_test.go +++ b/planner/core/logical_plan_trace_test.go @@ -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]", }, }, }, @@ -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", }, }, }, @@ -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]", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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]", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, }, @@ -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", }, }, @@ -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", }, }, diff --git a/planner/core/optimizer.go b/planner/core/optimizer.go index 89b156e632cea..36ef3b376bf55 100644 --- a/planner/core/optimizer.go +++ b/planner/core/optimizer.go @@ -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. diff --git a/planner/core/plan.go b/planner/core/plan.go index bd9d19a7de4e8..4c2c0c6ba93c5 100644 --- a/planner/core/plan.go +++ b/planner/core/plan.go @@ -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. @@ -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 } diff --git a/planner/core/rule_aggregation_elimination.go b/planner/core/rule_aggregation_elimination.go index 61d9e0f117e0d..9adca6936099d 100644 --- a/planner/core/rule_aggregation_elimination.go +++ b/planner/core/rule_aggregation_elimination.go @@ -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 } } @@ -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. diff --git a/planner/core/rule_aggregation_push_down.go b/planner/core/rule_aggregation_push_down.go index 7cc0548a7f57d..5f927befb8ee3 100644 --- a/planner/core/rule_aggregation_push_down.go +++ b/planner/core/rule_aggregation_push_down.go @@ -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(",") @@ -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(",") @@ -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) } diff --git a/planner/core/rule_eliminate_projection.go b/planner/core/rule_eliminate_projection.go index 0c377bd974703..0daaf4616185a 100644 --- a/planner/core/rule_eliminate_projection.go +++ b/planner/core/rule_eliminate_projection.go @@ -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(",") @@ -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) } diff --git a/planner/core/rule_join_elimination.go b/planner/core/rule_join_elimination.go index 6d4a750ea4356..c7ed935b8dc99 100644 --- a/planner/core/rule_join_elimination.go +++ b/planner/core/rule_join_elimination.go @@ -258,8 +258,10 @@ func appendOuterJoinEliminateTraceStep(join *LogicalJoin, outerPlan LogicalPlan, } buffer.WriteString("] are unique") return buffer.String() - }() - action := fmt.Sprintf("Outer join[%v] is eliminated and become %v[%v]", join.ID(), outerPlan.TP(), outerPlan.ID()) + } + action := func() string { + return fmt.Sprintf("Outer %v_%v is eliminated and become %v_%v", join.TP(), join.ID(), outerPlan.TP(), outerPlan.ID()) + } opt.appendStepToCurrent(join.ID(), join.TP(), reason, action) } @@ -274,7 +276,9 @@ func appendOuterJoinEliminateAggregationTraceStep(join *LogicalJoin, outerPlan L } buffer.WriteString("] in agg are from outer table, and the agg functions are duplicate agnostic") return buffer.String() - }() - action := fmt.Sprintf("Outer join[%v] is eliminated and become %v[%v]", join.ID(), outerPlan.TP(), outerPlan.ID()) + } + action := func() string { + return fmt.Sprintf("Outer %v_%v is eliminated and become %v_%v", join.TP(), join.ID(), outerPlan.TP(), outerPlan.ID()) + } opt.appendStepToCurrent(join.ID(), join.TP(), reason, action) } diff --git a/planner/core/rule_join_reorder.go b/planner/core/rule_join_reorder.go index dd29f7d3f1f30..e1ff17d70fd98 100644 --- a/planner/core/rule_join_reorder.go +++ b/planner/core/rule_join_reorder.go @@ -209,7 +209,9 @@ func appendJoinReorderTraceStep(tracer *joinReorderTrace, plan LogicalPlan, opt if len(tracer.initial) < 1 || len(tracer.final) < 1 { return } - action := fmt.Sprintf("join order becomes %v from original %v", tracer.final, tracer.initial) + action := func() string { + return fmt.Sprintf("join order becomes %v from original %v", tracer.final, tracer.initial) + } reason := func() string { buffer := bytes.NewBufferString("join cost during reorder: [") var joins []string @@ -225,7 +227,7 @@ func appendJoinReorderTraceStep(tracer *joinReorderTrace, plan LogicalPlan, opt } buffer.WriteString("]") return buffer.String() - }() + } opt.appendStepToCurrent(plan.ID(), plan.TP(), reason, action) } @@ -323,16 +325,16 @@ func (t *joinReorderTrace) traceJoinReorder(p LogicalPlan) { return } if len(t.initial) > 0 { - t.final = allJoinOrderToString(extractJoinAndDataSource(p.buildLogicalPlanTrace(p))) + t.final = allJoinOrderToString(extractJoinAndDataSource(p.buildLogicalPlanTrace())) return } - t.initial = allJoinOrderToString(extractJoinAndDataSource(p.buildLogicalPlanTrace(p))) + t.initial = allJoinOrderToString(extractJoinAndDataSource(p.buildLogicalPlanTrace())) } func (t *joinReorderTrace) appendLogicalJoinCost(join LogicalPlan, cost float64) { if t == nil || t.opt == nil || t.opt.tracer == nil { return } - joinMapKey := allJoinOrderToString(extractJoinAndDataSource(join.buildLogicalPlanTrace(join))) + joinMapKey := allJoinOrderToString(extractJoinAndDataSource(join.buildLogicalPlanTrace())) t.cost[joinMapKey] = cost } diff --git a/planner/core/rule_max_min_eliminate.go b/planner/core/rule_max_min_eliminate.go index 858f9005c2273..20d6fdba2857f 100644 --- a/planner/core/rule_max_min_eliminate.go +++ b/planner/core/rule_max_min_eliminate.go @@ -254,56 +254,56 @@ func appendEliminateSingleMaxMinTrace(agg *LogicalAggregation, sel *LogicalSelec action := func() string { buffer := bytes.NewBufferString("") if sel != nil { - buffer.WriteString(fmt.Sprintf("add selection[%v],", sel.ID())) + buffer.WriteString(fmt.Sprintf("add %v_%v,", sel.TP(), sel.ID())) } if sort != nil { - buffer.WriteString(fmt.Sprintf("add sort[%v],", sort.ID())) + buffer.WriteString(fmt.Sprintf("add %v_%v,", sort.TP(), sort.ID())) } - buffer.WriteString(fmt.Sprintf("add limit[%v] during eliminating agg[%v] %s function", limit.ID(), agg.ID(), agg.AggFuncs[0].Name)) + buffer.WriteString(fmt.Sprintf("add %v_%v during eliminating %v_%v %s function", limit.TP(), limit.ID(), agg.TP(), agg.ID(), agg.AggFuncs[0].Name)) return buffer.String() - }() + } reason := func() string { - buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v] has only one function[%s] without group by", agg.ID(), agg.AggFuncs[0].Name)) + buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v has only one function[%s] without group by", agg.TP(), agg.ID(), agg.AggFuncs[0].Name)) if sel != nil { - buffer.WriteString(fmt.Sprintf(", the columns in agg[%v] shouldn't be NULL and needs NULL to be filtered out", agg.ID())) + buffer.WriteString(fmt.Sprintf(", the columns in %v_%v shouldn't be NULL and needs NULL to be filtered out", agg.TP(), agg.ID())) } if sort != nil { - buffer.WriteString(fmt.Sprintf(", the columns in agg[%v] should be sorted", agg.ID())) + buffer.WriteString(fmt.Sprintf(", the columns in %v_%v should be sorted", agg.TP(), agg.ID())) } return buffer.String() - }() + } opt.appendStepToCurrent(agg.ID(), agg.TP(), reason, action) } func appendEliminateMultiMinMaxTraceStep(originAgg *LogicalAggregation, aggs []*LogicalAggregation, joins []*LogicalJoin, opt *logicalOptimizeOp) { action := func() string { - buffer := bytes.NewBufferString(fmt.Sprintf("agg[%v] splited into aggs[", originAgg.ID())) + buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v splited into [", originAgg.TP(), originAgg.ID())) for i, agg := range aggs { if i > 0 { buffer.WriteString(",") } - buffer.WriteString(fmt.Sprintf("%v", agg.ID())) + buffer.WriteString(fmt.Sprintf("%v_%v", agg.TP(), agg.ID())) } - buffer.WriteString("], and add joins[") + buffer.WriteString("], and add [") for i, join := range joins { if i > 0 { buffer.WriteString(",") } - buffer.WriteString(fmt.Sprintf("%v", join.ID())) + buffer.WriteString(fmt.Sprintf("%v_%v", join.TP(), join.ID())) } - buffer.WriteString(fmt.Sprintf("] to connect them during eliminating agg[%v] multi min/max functions", originAgg.ID())) + buffer.WriteString(fmt.Sprintf("] to connect them during eliminating %v_%v multi min/max functions", originAgg.TP(), originAgg.ID())) return buffer.String() - }() + } reason := func() string { - buffer := bytes.NewBufferString("each column is sorted and can benefit from index/primary key in agg[") + buffer := bytes.NewBufferString("each column is sorted and can benefit from index/primary key in [") for i, agg := range aggs { if i > 0 { buffer.WriteString(",") } - buffer.WriteString(fmt.Sprintf("%v", agg.ID())) + buffer.WriteString(fmt.Sprintf("%v_%v", agg.TP(), agg.ID())) } buffer.WriteString("] and none of them has group by clause") return buffer.String() - }() + } opt.appendStepToCurrent(originAgg.ID(), originAgg.TP(), reason, action) } diff --git a/planner/core/rule_partition_processor.go b/planner/core/rule_partition_processor.go index 04f572200232b..53a655c5ed932 100644 --- a/planner/core/rule_partition_processor.go +++ b/planner/core/rule_partition_processor.go @@ -1580,8 +1580,7 @@ func appendMakeUnionAllChildrenTranceStep(ds *DataSource, usedMap map[int64]mode appendNoPartitionChildTraceStep(ds, plan, opt) return } - action := "" - reason := "" + var action, reason func() string var used []model.PartitionDefinition for _, def := range usedMap { used = append(used, def) @@ -1590,22 +1589,26 @@ func appendMakeUnionAllChildrenTranceStep(ds *DataSource, usedMap map[int64]mode return used[i].ID < used[j].ID }) if len(children) == 1 { - action = fmt.Sprintf("Datasource[%v] becomes %s[%v]", ds.ID(), plan.TP(), plan.ID()) - reason = fmt.Sprintf("Datasource[%v] has one needed partition[%s] after pruning", ds.ID(), used[0].Name) + action = func() string { + return fmt.Sprintf("%v_%v becomes %s_%v", ds.TP(), ds.ID(), plan.TP(), plan.ID()) + } + reason = func() string { + return fmt.Sprintf("%v_%v has one needed partition[%s] after pruning", ds.TP(), ds.ID(), used[0].Name) + } } else { action = func() string { - buffer := bytes.NewBufferString(fmt.Sprintf("Datasource[%v] becomes %s[%v] with children[", ds.ID(), plan.TP(), plan.ID())) + buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v becomes %s_%v with children[", ds.TP(), ds.ID(), plan.TP(), plan.ID())) for i, child := range children { if i > 0 { buffer.WriteString(",") } - buffer.WriteString(fmt.Sprintf("%s[%v]", child.TP(), child.ID())) + buffer.WriteString(fmt.Sprintf("%s_%v", child.TP(), child.ID())) } buffer.WriteString("]") return buffer.String() - }() + } reason = func() string { - buffer := bytes.NewBufferString(fmt.Sprintf("Datasource[%v] has multiple needed partitions[", ds.ID())) + buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v has multiple needed partitions[", ds.TP(), ds.ID())) for i, u := range used { if i > 0 { buffer.WriteString(",") @@ -1614,13 +1617,17 @@ func appendMakeUnionAllChildrenTranceStep(ds *DataSource, usedMap map[int64]mode } buffer.WriteString("] after pruning") return buffer.String() - }() + } } opt.appendStepToCurrent(ds.ID(), ds.TP(), reason, action) } func appendNoPartitionChildTraceStep(ds *DataSource, dual LogicalPlan, opt *logicalOptimizeOp) { - action := fmt.Sprintf("Datasource[%v] becomes %v[%v]", ds.ID(), dual.TP(), dual.ID()) - reason := fmt.Sprintf("Datasource[%v] doesn't have needed partition table after pruning", ds.ID()) + action := func() string { + return fmt.Sprintf("%v_%v becomes %v_%v", ds.TP(), ds.ID(), dual.TP(), dual.ID()) + } + reason := func() string { + return fmt.Sprintf("%v_%v doesn't have needed partition table after pruning", ds.TP(), ds.ID()) + } opt.appendStepToCurrent(dual.ID(), dual.TP(), reason, action) } diff --git a/planner/core/rule_topn_push_down.go b/planner/core/rule_topn_push_down.go index 73ed5749bc57c..ecbb30a9cb17b 100644 --- a/planner/core/rule_topn_push_down.go +++ b/planner/core/rule_topn_push_down.go @@ -87,8 +87,7 @@ func (ls *LogicalSort) pushDownTopN(topN *LogicalTopN, opt *logicalOptimizeOp) L func (p *LogicalLimit) convertToTopN(opt *logicalOptimizeOp) *LogicalTopN { topn := LogicalTopN{Offset: p.Offset, Count: p.Count, limitHints: p.limitHints}.Init(p.ctx, p.blockOffset) - opt.appendStepToCurrent(topn.ID(), topn.TP(), "", fmt.Sprintf("%v_%v is converted into %v_%v", - p.TP(), p.ID(), topn.TP(), topn.ID())) + appendConvertTopNTraceStep(p, topn, opt) return topn } @@ -109,9 +108,7 @@ func (p *LogicalUnionAll) pushDownTopN(topN *LogicalTopN, opt *logicalOptimizeOp newTopN.ByItems = append(newTopN.ByItems, &util.ByItems{Expr: by.Expr, Desc: by.Desc}) } // newTopN to push down Union's child - opt.appendStepToCurrent(newTopN.ID(), newTopN.TP(), "", - fmt.Sprintf("%v_%v is added and pushed down across %v_%v", - newTopN.TP(), newTopN.ID(), p.TP(), p.ID())) + appendNewTopNTraceStep(topN, p, opt) } p.children[i] = child.pushDownTopN(newTopN, opt) } @@ -202,8 +199,12 @@ func (*pushDownTopNOptimizer) name() string { } func appendTopNPushDownTraceStep(parent LogicalPlan, child LogicalPlan, opt *logicalOptimizeOp) { - action := fmt.Sprintf("%v_%v is added as %v_%v's parent", parent.TP(), parent.ID(), child.TP(), child.ID()) - reason := fmt.Sprintf("%v is pushed down", parent.TP()) + action := func() string { + return fmt.Sprintf("%v_%v is added as %v_%v's parent", parent.TP(), parent.ID(), child.TP(), child.ID()) + } + reason := func() string { + return fmt.Sprintf("%v is pushed down", parent.TP()) + } opt.appendStepToCurrent(parent.ID(), parent.TP(), reason, action) } @@ -218,7 +219,7 @@ func appendTopNPushDownJoinTraceStep(p *LogicalJoin, topN *LogicalTopN, idx int, } buffer.WriteString("table") return buffer.String() - }() + } reason := func() string { buffer := bytes.NewBufferString(fmt.Sprintf("%v_%v's joinType is %v, and all ByItems[", p.TP(), p.ID(), p.JoinType.String())) for i, item := range topN.ByItems { @@ -235,7 +236,7 @@ func appendTopNPushDownJoinTraceStep(p *LogicalJoin, topN *LogicalTopN, idx int, } buffer.WriteString("table") return buffer.String() - }() + } opt.appendStepToCurrent(p.ID(), p.TP(), reason, action) } @@ -250,7 +251,29 @@ func appendSortPassByItemsTraceStep(sort *LogicalSort, topN *LogicalTopN, opt *l } buffer.WriteString(fmt.Sprintf("] to %v_%v", topN.TP(), topN.ID())) return buffer.String() - }() - reason := fmt.Sprintf("%v_%v is Limit originally", topN.TP(), topN.ID()) + } + reason := func() string { + return fmt.Sprintf("%v_%v is Limit originally", topN.TP(), topN.ID()) + } opt.appendStepToCurrent(sort.ID(), sort.TP(), reason, action) } + +func appendNewTopNTraceStep(topN *LogicalTopN, union *LogicalUnionAll, opt *logicalOptimizeOp) { + reason := func() string { + return "" + } + action := func() string { + return fmt.Sprintf("%v_%v is added and pushed down across %v_%v", topN.TP(), topN.ID(), union.TP(), union.ID()) + } + opt.appendStepToCurrent(topN.ID(), topN.TP(), reason, action) +} + +func appendConvertTopNTraceStep(p LogicalPlan, topN *LogicalTopN, opt *logicalOptimizeOp) { + reason := func() string { + return "" + } + action := func() string { + return fmt.Sprintf("%v_%v is converted into %v_%v", p.TP(), p.ID(), topN.TP(), topN.ID()) + } + opt.appendStepToCurrent(topN.ID(), topN.TP(), reason, action) +}