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: support cost detail framework #36641

Merged
merged 20 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 4 additions & 3 deletions planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,8 @@ func (e *Explain) RenderResult() error {
if e.Analyze && strings.ToLower(e.Format) == types.ExplainFormatTrueCardCost {
pp, ok := e.TargetPlan.(PhysicalPlan)
if ok {
if _, err := pp.GetPlanCost(property.RootTaskType, CostFlagRecalculate|CostFlagUseTrueCardinality); err != nil {
if _, err := pp.GetPlanCost(property.RootTaskType,
NewDefaultPlanCostOption().WithCostFlag(CostFlagRecalculate|CostFlagUseTrueCardinality)); err != nil {
return err
}
} else {
Expand Down Expand Up @@ -843,7 +844,7 @@ func (e *Explain) getOperatorInfo(p Plan, id string) (string, string, string, st
estCost := "N/A"
if pp, ok := p.(PhysicalPlan); ok {
if p.SCtx().GetSessionVars().EnableNewCostInterface {
planCost, _ := pp.GetPlanCost(property.RootTaskType, 0)
planCost, _ := pp.GetPlanCost(property.RootTaskType, NewDefaultPlanCostOption())
estCost = strconv.FormatFloat(planCost, 'f', 2, 64)
} else {
estCost = strconv.FormatFloat(pp.Cost(), 'f', 2, 64)
Expand Down Expand Up @@ -953,7 +954,7 @@ func binaryOpFromFlatOp(explainCtx sessionctx.Context, op *FlatOperator, out *ti
if op.IsPhysicalPlan {
p := op.Origin.(PhysicalPlan)
if p.SCtx().GetSessionVars().EnableNewCostInterface {
out.Cost, _ = p.GetPlanCost(property.RootTaskType, 0)
out.Cost, _ = p.GetPlanCost(property.RootTaskType, NewDefaultPlanCostOption())
} else {
out.Cost = p.Cost()
}
Expand Down
38 changes: 23 additions & 15 deletions planner/core/find_best_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ func (p *baseLogicalPlan) rebuildChildTasks(childTasks *[]task, pp PhysicalPlan,
return nil
}

func (p *baseLogicalPlan) enumeratePhysicalPlans4Task(physicalPlans []PhysicalPlan, prop *property.PhysicalProperty, addEnforcer bool, planCounter *PlanCounterTp, opt *physicalOptimizeOp) (task, int64, error) {
func (p *baseLogicalPlan) enumeratePhysicalPlans4Task(physicalPlans []PhysicalPlan,
prop *property.PhysicalProperty, addEnforcer bool, planCounter *PlanCounterTp, opt *physicalOptimizeOp) (task, int64, error) {
var bestTask task = invalidTask
var curCntPlan, cntPlan int64
childTasks := make([]task, 0, len(p.children))
Expand Down Expand Up @@ -278,7 +279,7 @@ func (p *baseLogicalPlan) enumeratePhysicalPlans4Task(physicalPlans []PhysicalPl
}
opt.appendCandidate(p, curTask.plan(), prop)
// Get the most efficient one.
if curIsBetter, err := compareTaskCost(p.ctx, curTask, bestTask); err != nil {
if curIsBetter, err := compareTaskCost(p.ctx, curTask, bestTask, opt); err != nil {
return nil, 0, err
} else if curIsBetter {
bestTask = curTask
Expand All @@ -288,12 +289,12 @@ func (p *baseLogicalPlan) enumeratePhysicalPlans4Task(physicalPlans []PhysicalPl
}

// compareTaskCost compares cost of curTask and bestTask and returns whether curTask's cost is smaller than bestTask's.
func compareTaskCost(_ sessionctx.Context, curTask, bestTask task) (curIsBetter bool, err error) {
curCost, curInvalid, err := getTaskPlanCost(curTask)
func compareTaskCost(_ sessionctx.Context, curTask, bestTask task, op *physicalOptimizeOp) (curIsBetter bool, err error) {
curCost, curInvalid, err := getTaskPlanCost(curTask, op)
if err != nil {
return false, err
}
bestCost, bestInvalid, err := getTaskPlanCost(bestTask)
bestCost, bestInvalid, err := getTaskPlanCost(bestTask, op)
if err != nil {
return false, err
}
Expand All @@ -309,7 +310,7 @@ func compareTaskCost(_ sessionctx.Context, curTask, bestTask task) (curIsBetter
// getTaskPlanCost returns the cost of this task.
// The new cost interface will be used if EnableNewCostInterface is true.
// The second returned value indicates whether this task is valid.
func getTaskPlanCost(t task) (float64, bool, error) {
func getTaskPlanCost(t task, op *physicalOptimizeOp) (float64, bool, error) {
if t.invalid() {
return math.MaxFloat64, true, nil
}
Expand All @@ -329,7 +330,7 @@ func getTaskPlanCost(t task) (float64, bool, error) {
default:
return 0, false, errors.New("unknown task type")
}
cost, err := t.plan().GetPlanCost(taskType, 0)
cost, err := t.plan().GetPlanCost(taskType, NewDefaultPlanCostOption().WithOptimizeTracer(op))
return cost, false, err
}

Expand Down Expand Up @@ -359,6 +360,13 @@ func (op *physicalOptimizeOp) appendCandidate(lp LogicalPlan, pp PhysicalPlan, p
pp.appendChildCandidate(op)
}

func (op *physicalOptimizeOp) appendPlanCostDetail(detail *tracing.PhysicalPlanCostDetail) {
if op == nil || op.tracer == nil {
return
}
op.tracer.PhysicalPlanCostDetails[detail.GetPlanID()] = detail
}

// findBestTask implements LogicalPlan interface.
func (p *baseLogicalPlan) findBestTask(prop *property.PhysicalProperty, planCounter *PlanCounterTp, opt *physicalOptimizeOp) (bestTask task, cntPlan int64, err error) {
// If p is an inner plan in an IndexJoin, the IndexJoin will generate an inner plan by itself,
Expand Down Expand Up @@ -449,7 +457,7 @@ func (p *baseLogicalPlan) findBestTask(prop *property.PhysicalProperty, planCoun
goto END
}
opt.appendCandidate(p, curTask.plan(), prop)
if curIsBetter, err := compareTaskCost(p.ctx, curTask, bestTask); err != nil {
if curIsBetter, err := compareTaskCost(p.ctx, curTask, bestTask, opt); err != nil {
return nil, 0, err
} else if curIsBetter {
bestTask = curTask
Expand Down Expand Up @@ -881,7 +889,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
}
appendCandidate(ds, idxMergeTask, prop, opt)

curIsBetter, err := compareTaskCost(ds.ctx, idxMergeTask, t)
curIsBetter, err := compareTaskCost(ds.ctx, idxMergeTask, t, opt)
if err != nil {
return nil, 0, err
}
Expand Down Expand Up @@ -973,7 +981,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
cntPlan++
planCounter.Dec(1)
}
curIsBetter, cerr := compareTaskCost(ds.ctx, pointGetTask, t)
curIsBetter, cerr := compareTaskCost(ds.ctx, pointGetTask, t, opt)
if cerr != nil {
return nil, 0, cerr
}
Expand Down Expand Up @@ -1007,7 +1015,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
planCounter.Dec(1)
}
appendCandidate(ds, tblTask, prop, opt)
curIsBetter, err := compareTaskCost(ds.ctx, tblTask, t)
curIsBetter, err := compareTaskCost(ds.ctx, tblTask, t, opt)
if err != nil {
return nil, 0, err
}
Expand All @@ -1032,7 +1040,7 @@ func (ds *DataSource) findBestTask(prop *property.PhysicalProperty, planCounter
planCounter.Dec(1)
}
appendCandidate(ds, idxTask, prop, opt)
curIsBetter, err := compareTaskCost(ds.ctx, idxTask, t)
curIsBetter, err := compareTaskCost(ds.ctx, idxTask, t, opt)
if err != nil {
return nil, 0, err
}
Expand Down Expand Up @@ -1985,7 +1993,7 @@ func (ds *DataSource) convertToSampleTable(prop *property.PhysicalProperty,
}, nil
}

func (ds *DataSource) convertToPointGet(prop *property.PhysicalProperty, candidate *candidatePath, _ *physicalOptimizeOp) (task task) {
func (ds *DataSource) convertToPointGet(prop *property.PhysicalProperty, candidate *candidatePath, opt *physicalOptimizeOp) (task task) {
if !prop.IsSortItemEmpty() && !candidate.isMatchProp {
return invalidTask
}
Expand Down Expand Up @@ -2031,7 +2039,7 @@ func (ds *DataSource) convertToPointGet(prop *property.PhysicalProperty, candida
pointGetPlan.UnsignedHandle = mysql.HasUnsignedFlag(ds.handleCols.GetCol(0).RetType.GetFlag())
pointGetPlan.PartitionInfo = partitionInfo
pointGetPlan.accessCols = ds.TblCols
cost = pointGetPlan.GetCost()
cost = pointGetPlan.GetCost(opt)
// Add filter condition to table plan now.
if len(candidate.path.TableFilters) > 0 {
sessVars := ds.ctx.GetSessionVars()
Expand All @@ -2053,7 +2061,7 @@ func (ds *DataSource) convertToPointGet(prop *property.PhysicalProperty, candida
} else {
pointGetPlan.accessCols = ds.TblCols
}
cost = pointGetPlan.GetCost()
cost = pointGetPlan.GetCost(opt)
// Add index condition to table plan now.
if len(candidate.path.IndexFilters)+len(candidate.path.TableFilters) > 0 {
sessVars := ds.ctx.GetSessionVars()
Expand Down
5 changes: 4 additions & 1 deletion planner/core/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,10 @@ func physicalOptimize(logic LogicalPlan, planCounter *PlanCounterTp) (plan Physi
opt := defaultPhysicalOptimizeOption()
stmtCtx := logic.SCtx().GetSessionVars().StmtCtx
if stmtCtx.EnableOptimizeTrace {
tracer := &tracing.PhysicalOptimizeTracer{Candidates: make(map[int]*tracing.CandidatePlanTrace)}
tracer := &tracing.PhysicalOptimizeTracer{
PhysicalPlanCostDetails: make(map[int]*tracing.PhysicalPlanCostDetail),
Candidates: make(map[int]*tracing.CandidatePlanTrace),
}
opt = opt.withEnableOptimizeTracer(tracer)
defer func() {
if err == nil {
Expand Down
31 changes: 30 additions & 1 deletion planner/core/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ type PhysicalPlan interface {
Plan

// GetPlanCost calculates the cost of the plan if it has not been calculated yet and returns the cost.
GetPlanCost(taskType property.TaskType, costFlag uint64) (float64, error)
GetPlanCost(taskType property.TaskType, option *PlanCostOption) (float64, error)

// attach2Task makes the current physical plan as the father of task's physicalPlan and updates the cost of
// current task. If the child's task is cop task, some operator may close this task and return a new rootTask.
Expand Down Expand Up @@ -381,6 +381,35 @@ type PhysicalPlan interface {
appendChildCandidate(op *physicalOptimizeOp)
}

// NewDefaultPlanCostOption returns PlanCostOption
func NewDefaultPlanCostOption() *PlanCostOption {
return &PlanCostOption{}
}

// PlanCostOption indicates option during GetPlanCost
type PlanCostOption struct {
CostFlag uint64
tracer *physicalOptimizeOp
}

// WithCostFlag set costflag
func (op *PlanCostOption) WithCostFlag(flag uint64) *PlanCostOption {
if op == nil {
return nil
}
op.CostFlag = flag
return op
}

// WithOptimizeTracer set tracer
func (op *PlanCostOption) WithOptimizeTracer(tracer *physicalOptimizeOp) *PlanCostOption {
if op == nil {
return nil
}
op.tracer = tracer
return op
}

type baseLogicalPlan struct {
basePlan

Expand Down
Loading