Skip to content

Commit

Permalink
planner: show operator cost formulas under 'explain format=true_card_…
Browse files Browse the repository at this point in the history
…cost' (#38405)

ref #36243
  • Loading branch information
qw4990 authored Oct 11, 2022
1 parent a32941c commit f343ffe
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 28 deletions.
26 changes: 19 additions & 7 deletions planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,14 @@ func (e *Explain) prepareSchema() error {
switch {
case (format == types.ExplainFormatROW || format == types.ExplainFormatBrief) && (!e.Analyze && e.RuntimeStatsColl == nil):
fieldNames = []string{"id", "estRows", "task", "access object", "operator info"}
case format == types.ExplainFormatVerbose || format == types.ExplainFormatTrueCardCost:
case format == types.ExplainFormatVerbose:
if e.Analyze || e.RuntimeStatsColl != nil {
fieldNames = []string{"id", "estRows", "estCost", "actRows", "task", "access object", "execution info", "operator info", "memory", "disk"}
} else {
fieldNames = []string{"id", "estRows", "estCost", "task", "access object", "operator info"}
}
case format == types.ExplainFormatTrueCardCost:
fieldNames = []string{"id", "estRows", "estCost", "costFormula", "actRows", "task", "access object", "execution info", "operator info", "memory", "disk"}
case (format == types.ExplainFormatROW || format == types.ExplainFormatBrief) && (e.Analyze || e.RuntimeStatsColl != nil):
fieldNames = []string{"id", "estRows", "actRows", "task", "access object", "execution info", "operator info", "memory", "disk"}
case format == types.ExplainFormatDOT:
Expand Down Expand Up @@ -850,14 +852,17 @@ func (e *Explain) prepareOperatorInfo(p Plan, taskType, id string) {
return
}

estRows, estCost, accessObject, operatorInfo := e.getOperatorInfo(p, id)
estRows, estCost, costFormula, accessObject, operatorInfo := e.getOperatorInfo(p, id)

var row []string
if e.Analyze || e.RuntimeStatsColl != nil {
row = []string{id, estRows}
if strings.ToLower(e.Format) == types.ExplainFormatVerbose || strings.ToLower(e.Format) == types.ExplainFormatTrueCardCost {
row = append(row, estCost)
}
if strings.ToLower(e.Format) == types.ExplainFormatTrueCardCost {
row = append(row, costFormula)
}
actRows, analyzeInfo, memoryInfo, diskInfo := getRuntimeInfoStr(e.ctx, p, e.RuntimeStatsColl)
row = append(row, actRows, taskType, accessObject, analyzeInfo, operatorInfo, memoryInfo, diskInfo)
} else {
Expand All @@ -870,24 +875,31 @@ func (e *Explain) prepareOperatorInfo(p Plan, taskType, id string) {
e.Rows = append(e.Rows, row)
}

func (e *Explain) getOperatorInfo(p Plan, id string) (string, string, string, string) {
func (e *Explain) getOperatorInfo(p Plan, id string) (string, string, string, string, string) {
// For `explain for connection` statement, `e.ExplainRows` will be set.
for _, row := range e.ExplainRows {
if len(row) < 5 {
panic("should never happen")
}
if row[0] == id {
return row[1], "N/A", row[3], row[4]
return row[1], "N/A", "N/A", row[3], row[4]
}
}
estRows := "N/A"
if si := p.statsInfo(); si != nil {
estRows = strconv.FormatFloat(si.RowCount, 'f', 2, 64)
}
estCost := "N/A"
costFormula := "N/A"
if pp, ok := p.(PhysicalPlan); ok {
planCost, _ := getPlanCost(pp, property.RootTaskType, NewDefaultPlanCostOption())
estCost = strconv.FormatFloat(planCost, 'f', 2, 64)
if e.ctx != nil && e.ctx.GetSessionVars().CostModelVersion == modelVer2 {
costVer2, _ := pp.getPlanCostVer2(property.RootTaskType, NewDefaultPlanCostOption())
estCost = strconv.FormatFloat(costVer2.cost, 'f', 2, 64)
costFormula = costVer2.formula
} else {
planCost, _ := getPlanCost(pp, property.RootTaskType, NewDefaultPlanCostOption())
estCost = strconv.FormatFloat(planCost, 'f', 2, 64)
}
}
var accessObject, operatorInfo string
if plan, ok := p.(dataAccesser); ok {
Expand All @@ -899,7 +911,7 @@ func (e *Explain) getOperatorInfo(p Plan, id string) (string, string, string, st
}
operatorInfo = p.ExplainInfo()
}
return estRows, estCost, accessObject, operatorInfo
return estRows, estCost, costFormula, accessObject, operatorInfo
}

// BinaryPlanStrFromFlatPlan generates the compressed and encoded binary plan from a FlatPhysicalPlan.
Expand Down
50 changes: 29 additions & 21 deletions planner/core/plan_cost_ver2.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (p *basePhysicalPlan) getPlanCostVer2(taskType property.TaskType, option *P
p.planCostVer2 = sumCostVer2(childCosts...)
}
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -76,7 +76,7 @@ func (p *PhysicalSelection) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = sumCostVer2(filterCost, childCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -100,7 +100,7 @@ func (p *PhysicalProjection) getPlanCostVer2(taskType property.TaskType, option

p.planCostVer2 = sumCostVer2(childCost, divCostVer2(projCost, concurrency))
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -117,7 +117,7 @@ func (p *PhysicalIndexScan) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = scanCostVer2(option, rows, rowSize, scanFactor)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -140,7 +140,7 @@ func (p *PhysicalTableScan) getPlanCostVer2(taskType property.TaskType, option *
}

p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -168,7 +168,7 @@ func (p *PhysicalIndexReader) getPlanCostVer2(taskType property.TaskType, option

p.planCostVer2 = divCostVer2(sumCostVer2(childCost, netCost, seekCost), concurrency)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -203,7 +203,7 @@ func (p *PhysicalTableReader) getPlanCostVer2(taskType property.TaskType, option
!hasCostFlag(option.CostFlag, CostFlagRecalculate) { // show the real cost in explain-statements
p.planCostVer2 = divCostVer2(p.planCostVer2, 1000000000)
}
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -259,7 +259,7 @@ func (p *PhysicalIndexLookUpReader) getPlanCostVer2(taskType property.TaskType,

p.planCostVer2 = sumCostVer2(indexSideCost, divCostVer2(sumCostVer2(tableSideCost, doubleReadCost), doubleReadConcurrency))
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -307,7 +307,7 @@ func (p *PhysicalIndexMergeReader) getPlanCostVer2(taskType property.TaskType, o

p.planCostVer2 = sumCostVer2(tableSideCost, sumIndexSideCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -362,7 +362,7 @@ func (p *PhysicalSort) getPlanCostVer2(taskType property.TaskType, option *PlanC

p.planCostVer2 = sumCostVer2(childCost, sortCPUCost, sortMemCost, sortDiskCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -394,7 +394,7 @@ func (p *PhysicalTopN) getPlanCostVer2(taskType property.TaskType, option *PlanC

p.planCostVer2 = sumCostVer2(childCost, topNCPUCost, topNMemCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -417,7 +417,7 @@ func (p *PhysicalStreamAgg) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = sumCostVer2(childCost, aggCost, groupCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -446,7 +446,7 @@ func (p *PhysicalHashAgg) getPlanCostVer2(taskType property.TaskType, option *Pl

p.planCostVer2 = sumCostVer2(childCost, divCostVer2(sumCostVer2(aggCost, groupCost, hashBuildCost, hashProbeCost), concurrency))
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -476,7 +476,7 @@ func (p *PhysicalMergeJoin) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = sumCostVer2(leftChildCost, rightChildCost, filterCost, groupCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -520,7 +520,7 @@ func (p *PhysicalHashJoin) getPlanCostVer2(taskType property.TaskType, option *P
p.planCostVer2 = sumCostVer2(buildChildCost, probeChildCost, buildHashCost, buildFilterCost,
divCostVer2(sumCostVer2(probeFilterCost, probeHashCost), concurrency))
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand Down Expand Up @@ -560,7 +560,7 @@ func (p *PhysicalIndexJoin) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = sumCostVer2(buildChildCost, buildFilterCost, divCostVer2(sumCostVer2(probeCost, probeFilterCost), probeConcurrency))
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

func (p *PhysicalIndexHashJoin) getPlanCostVer2(taskType property.TaskType, option *PlanCostOption) (costVer2, error) {
Expand Down Expand Up @@ -601,7 +601,7 @@ func (p *PhysicalApply) getPlanCostVer2(taskType property.TaskType, option *Plan

p.planCostVer2 = sumCostVer2(buildChildCost, buildFilterCost, probeCost, probeFilterCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 calculates the cost of the plan if it has not been calculated yet and returns the cost.
Expand All @@ -622,7 +622,7 @@ func (p *PhysicalUnionAll) getPlanCostVer2(taskType property.TaskType, option *P
}
p.planCostVer2 = divCostVer2(sumCostVer2(childCosts...), concurrency)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -644,7 +644,7 @@ func (p *PhysicalExchangeReceiver) getPlanCostVer2(taskType property.TaskType, o

p.planCostVer2 = sumCostVer2(childCost, netCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -668,7 +668,7 @@ func (p *PointGetPlan) getPlanCostVer2(taskType property.TaskType, option *PlanC

p.planCostVer2 = sumCostVer2(netCost, seekCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

// getPlanCostVer2 returns the plan-cost of this sub-plan, which is:
Expand All @@ -693,7 +693,7 @@ func (p *BatchPointGetPlan) getPlanCostVer2(taskType property.TaskType, option *

p.planCostVer2 = sumCostVer2(netCost, seekCost)
p.planCostInit = true
return p.planCostVer2, nil
return p.planCostVer2.label(p), nil
}

func scanCostVer2(option *PlanCostOption, rows, rowSize float64, scanFactor costVer2Factor) costVer2 {
Expand Down Expand Up @@ -929,6 +929,14 @@ type costVer2 struct {
formula string // It used to trace the cost calculation.
}

func (c costVer2) label(p PhysicalPlan) costVer2 {
if !c.trace {
return c
}
c.formula = p.ExplainID().String()
return c
}

func traceCost(option *PlanCostOption) bool {
if option != nil && hasCostFlag(option.CostFlag, CostFlagTrace) {
return true
Expand Down
22 changes: 22 additions & 0 deletions planner/core/plan_cost_ver2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,28 @@ func TestCostModelVer2(t *testing.T) {
}
}

func TestCostModelShowFormula(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`create table t (a int)`)
tk.MustExec("insert into t values (1), (2), (3)")
tk.MustExec("set @@tidb_cost_model_version=2")

tk.MustExecToErr("explain format='true_card_cost' select * from t") // 'true_card_cost' must work with 'explain analyze'
plan := tk.MustQuery("explain analyze format='true_card_cost' select * from t where a<3").Rows()
actual := make([][]interface{}, 0, len(plan))
for _, row := range plan {
actual = append(actual, []interface{}{row[0], row[3]}) // id,costFormula
fmt.Println(actual)
}
require.Equal(t, actual, [][]interface{}{
{"TableReader_7", "((Selection_6) + (net(2*rowsize(16)*tidb_kv_net_factor(8))) + (seek(tasks(20)*tidb_request_factor(9.5e+06))))/15"},
{"└─Selection_6", "(cpu(3*filters(1)*tikv_cpu_factor(30))) + (TableFullScan_5)"},
{" └─TableFullScan_5", "scan(3*logrowsize(29)*tikv_scan_factor(100))"},
})
}

func TestCostModelTraceVer2(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down
4 changes: 4 additions & 0 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4641,6 +4641,10 @@ func (b *PlanBuilder) buildTrace(trace *ast.TraceStmt) (Plan, error) {
}

func (b *PlanBuilder) buildExplainPlan(targetPlan Plan, format string, explainRows [][]string, analyze bool, execStmt ast.StmtNode, runtimeStats *execdetails.RuntimeStatsColl) (Plan, error) {
if strings.ToLower(format) == types.ExplainFormatTrueCardCost && !analyze {
return nil, errors.Errorf("'explain format=%v' cannot work without 'analyze', please use 'explain analyze format=%v'", format, format)
}

p := &Explain{
TargetPlan: targetPlan,
Format: format,
Expand Down

0 comments on commit f343ffe

Please sign in to comment.