Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#56387
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
terry1purcell authored and ti-chi-bot committed Sep 29, 2024
1 parent 3edb7a3 commit 106b64f
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -417,17 +417,22 @@
" TableReader root ",
" └─ExchangeSender cop[tiflash] ",
" └─Projection cop[tiflash] test.t1.a",
" └─Selection cop[tiflash] gt(test.t1.b, ?)",
" └─TableFullScan cop[tiflash] table:t1, range:[?,?], pushed down filter:gt(test.t1.a, ?), keep order:false"
" └─Selection cop[tiflash] gt(test.t1.a, ?)",
" └─TableFullScan cop[tiflash] table:t1, range:[?,?], pushed down filter:gt(test.t1.b, ?), keep order:false"
]
},
{
"SQL": "explain select * from t1 where a>1 and b>1 and c>1",
"Plan": [
" TableReader root ",
" └─ExchangeSender cop[tiflash] ",
<<<<<<< HEAD
" └─Selection cop[tiflash] gt(test.t1.a, ?)",
" └─TableFullScan cop[tiflash] table:t1, range:[?,?], pushed down filter:gt(test.t1.b, ?), gt(test.t1.c, ?), keep order:false"
=======
" └─Selection cop[tiflash] gt(test.t1.c, ?)",
" └─TableFullScan cop[tiflash] table:t1, range:[?,?], pushed down filter:gt(test.t1.a, ?), gt(test.t1.b, ?), keep order:false"
>>>>>>> 4df3389c263 (planner: Set minimum cost to avoid parent multiplication cost discrepancies (#56387))
]
},
{
Expand Down
7 changes: 6 additions & 1 deletion pkg/planner/core/plan_cost_ver2.go
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ func scanCostVer2(option *PlanCostOption, rows, rowSize float64, scanFactor cost
}
return newCostVer2(option, scanFactor,
// rows * log(row-size) * scanFactor, log2 from experiments
rows*math.Log2(rowSize)*scanFactor.Value,
rows*max(math.Log2(rowSize), 0)*scanFactor.Value,
func() string { return fmt.Sprintf("scan(%v*logrowsize(%v)*%v)", rows, rowSize, scanFactor) })
}

Expand Down Expand Up @@ -851,8 +851,13 @@ func orderCostVer2(option *PlanCostOption, rows, n float64, byItems []*util.ByIt
exprCost := newCostVer2(option, cpuFactor,
rows*float64(numFuncs)*cpuFactor.Value,
func() string { return fmt.Sprintf("exprCPU(%v*%v*%v)", rows, numFuncs, cpuFactor) })
<<<<<<< HEAD
orderCost := newCostVer2(option, cpuFactor,
rows*math.Log2(n)*cpuFactor.Value,
=======
orderCost := costusage.NewCostVer2(option, cpuFactor,
max(rows*math.Log2(n), 0)*cpuFactor.Value,
>>>>>>> 4df3389c263 (planner: Set minimum cost to avoid parent multiplication cost discrepancies (#56387))
func() string { return fmt.Sprintf("orderCPU(%v*log(%v)*%v)", rows, n, cpuFactor) })
return sumCostVer2(exprCost, orderCost)
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,19 @@ func (p *PhysicalIndexJoin) attach2Task(tasks ...task) task {
// RowSize for cost model ver2 is simplified, always use this function to calculate row size.
func getAvgRowSize(stats *property.StatsInfo, cols []*expression.Column) (size float64) {
if stats.HistColl != nil {
<<<<<<< HEAD
size = cardinality.GetAvgRowSizeListInDisk(stats.HistColl, cols)
} else {
// Estimate using just the type info.
for _, col := range cols {
size += float64(chunk.EstimateTypeWidth(col.GetType()))
=======
size = max(cardinality.GetAvgRowSizeDataInDiskByRows(stats.HistColl, cols), 0)
} else {
// Estimate using just the type info.
for _, col := range cols {
size += max(float64(chunk.EstimateTypeWidth(col.GetStaticType())), 0)
>>>>>>> 4df3389c263 (planner: Set minimum cost to avoid parent multiplication cost discrepancies (#56387))
}
}
return
Expand Down
180 changes: 180 additions & 0 deletions pkg/planner/util/costusage/cost_misc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Copyright 2024 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package costusage

import (
"fmt"
"strconv"

"github.com/pingcap/tidb/pkg/planner/util/optimizetrace"
)

// optimizetrace and costusage is isolated from `util` because `core/base` depended on them
// for interface definition. Ideally, the dependency chain should be:
//
// `base` <- `util`/`util.coreusage` <- `core`
// ^ +---------------^ |
// +------------------------------------+
//
// since `base` depended on optimizetrace and costusage for definition, we should separate
// them out of `util`/`util.coreusage` to avoid import cycle.
//
// util.optimizetrace/util.costusage <- `base` <- `util`/`util.coreusage` <- `core`
// ^ ^ ||
// | +------------------------------------+|
// +-------------------------------------------------------------+

const (
// CostFlagRecalculate indicates the optimizer to ignore cached cost and recalculate it again.
CostFlagRecalculate uint64 = 1 << iota

// CostFlagUseTrueCardinality indicates the optimizer to use true cardinality to calculate the cost.
CostFlagUseTrueCardinality

// CostFlagTrace indicates whether to trace the cost calculation.
CostFlagTrace
)

func init() {
optimizetrace.CostFlagTrace = CostFlagTrace
}

// CostVer2 is a structure of cost basic of version2
type CostVer2 struct {
cost float64
trace *CostTrace
}

// GetCost returns the cost value of the costVer2
func (c *CostVer2) GetCost() float64 {
return max(c.cost, 0)
}

// GetTrace returns the trace of current costVer2
func (c *CostVer2) GetTrace() *CostTrace {
return c.trace
}

// CostTrace record the basic factor and formula in cost est.
type CostTrace struct {
factorCosts map[string]float64 // map[factorName]cost, used to calibrate the cost model
formula string // It used to trace the cost calculation.
}

// GetFormula return the formula of current costTrace.
func (c *CostTrace) GetFormula() string {
return c.formula
}

// GetFactorCosts return the factors of current costTrace.
func (c *CostTrace) GetFactorCosts() map[string]float64 {
return c.factorCosts
}

// NewZeroCostVer2 return a new zero costVer2.
func NewZeroCostVer2(trace bool) (ret CostVer2) {
if trace {
ret.trace = &CostTrace{make(map[string]float64), ""}
}
return
}

// HasCostFlag indicates whether the costFlag has the flag.
func HasCostFlag(costFlag, flag uint64) bool {
return (costFlag & flag) > 0
}

// TraceCost indicates whether to trace cost.
func TraceCost(option *optimizetrace.PlanCostOption) bool {
if option != nil && HasCostFlag(option.CostFlag, CostFlagTrace) {
return true
}
return false
}

// NewCostVer2 is the constructor of CostVer2.
func NewCostVer2(option *optimizetrace.PlanCostOption, factor CostVer2Factor, cost float64,
lazyFormula func() string) (ret CostVer2) {
ret.cost = cost
if TraceCost(option) {
ret.trace = &CostTrace{make(map[string]float64), ""}
ret.trace.factorCosts[factor.Name] = cost
ret.trace.formula = lazyFormula()
}
return ret
}

// CostVer2Factor is a record of internal cost factor.
type CostVer2Factor struct {
Name string
Value float64
}

// String return the current CostVer2Factor's format string.
func (f CostVer2Factor) String() string {
return fmt.Sprintf("%s(%v)", f.Name, f.Value)
}

// SumCostVer2 sum the cost up of all the passed args.
func SumCostVer2(costs ...CostVer2) (ret CostVer2) {
if len(costs) == 0 {
return
}
for _, c := range costs {
ret.cost += c.cost
if c.trace != nil {
if ret.trace == nil { // init
ret.trace = &CostTrace{make(map[string]float64), ""}
}
for factor, factorCost := range c.trace.factorCosts {
ret.trace.factorCosts[factor] += factorCost
}
if ret.trace.formula != "" {
ret.trace.formula += " + "
}
ret.trace.formula += "(" + c.trace.formula + ")"
}
}
return ret
}

// DivCostVer2 is div utility func of CostVer2.
func DivCostVer2(cost CostVer2, denominator float64) (ret CostVer2) {
ret.cost = cost.cost / denominator
if cost.trace != nil {
ret.trace = &CostTrace{make(map[string]float64), ""}
for f, c := range cost.trace.factorCosts {
ret.trace.factorCosts[f] = c / denominator
}
ret.trace.formula = "(" + cost.trace.formula + ")/" + strconv.FormatFloat(denominator, 'f', 2, 64)
}
return ret
}

// MulCostVer2 is mul utility func of CostVer2.
func MulCostVer2(cost CostVer2, scale float64) (ret CostVer2) {
ret.cost = cost.cost * scale
if cost.trace != nil {
ret.trace = &CostTrace{make(map[string]float64), ""}
for f, c := range cost.trace.factorCosts {
ret.trace.factorCosts[f] = c * scale
}
ret.trace.formula = "(" + cost.trace.formula + ")*" + strconv.FormatFloat(scale, 'f', 2, 64)
}
return ret
}

// ZeroCostVer2 is a pre-defined zero CostVer2.
var ZeroCostVer2 = NewZeroCostVer2(false)

0 comments on commit 106b64f

Please sign in to comment.