github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/optimizer/plan/cost.go (about)

     1  // Copyright 2015 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package plan
    15  
    16  import (
    17  	"math"
    18  )
    19  
    20  // Pre-defined cost factors.
    21  const (
    22  	FullRangeCount   = 10000
    23  	HalfRangeCount   = 4000
    24  	MiddleRangeCount = 100
    25  	RowCost          = 1.0
    26  	IndexCost        = 1.1
    27  	SortCost         = 2.0
    28  	FilterRate       = 0.5
    29  )
    30  
    31  // CostEstimator estimates the cost of a plan.
    32  
    33  // Enter implements Visitor Enter interface.
    34  func estimate(p Plan) {
    35  	var child Plan
    36  	for _, c := range p.GetChildren() {
    37  		estimate(c)
    38  		child = c
    39  	}
    40  	switch v := p.(type) {
    41  	case *IndexScan:
    42  		indexScan(v)
    43  	case *Limit:
    44  		v.rowCount = child.RowCount()
    45  		v.startupCost = child.StartupCost()
    46  		v.totalCost = child.TotalCost()
    47  	case *SelectFields:
    48  		if child != nil {
    49  			v.startupCost = child.StartupCost()
    50  			v.rowCount = child.RowCount()
    51  			v.totalCost = child.TotalCost()
    52  		}
    53  	case *SelectLock:
    54  		v.startupCost = child.StartupCost()
    55  		v.rowCount = child.RowCount()
    56  		v.totalCost = child.TotalCost()
    57  	case *Sort:
    58  		// Sort plan must retrieve all the rows before returns the first row.
    59  		v.startupCost = child.TotalCost() + child.RowCount()*SortCost
    60  		if v.limit == 0 {
    61  			v.rowCount = child.RowCount()
    62  		} else {
    63  			v.rowCount = math.Min(child.RowCount(), v.limit)
    64  		}
    65  		v.totalCost = v.startupCost + v.rowCount*RowCost
    66  	case *TableScan:
    67  		tableScan(v)
    68  	}
    69  }
    70  
    71  func tableScan(v *TableScan) {
    72  	var rowCount float64 = FullRangeCount
    73  	for _, con := range v.AccessConditions {
    74  		rowCount *= guesstimateFilterRate(con)
    75  	}
    76  	v.startupCost = 0
    77  	if v.limit == 0 {
    78  		// limit is zero means no limit.
    79  		v.rowCount = rowCount
    80  	} else {
    81  		v.rowCount = math.Min(rowCount, v.limit)
    82  	}
    83  	v.totalCost = v.rowCount * RowCost
    84  }
    85  
    86  func indexScan(v *IndexScan) {
    87  	var rowCount float64 = FullRangeCount
    88  	for _, con := range v.AccessConditions {
    89  		rowCount *= guesstimateFilterRate(con)
    90  	}
    91  	v.startupCost = 0
    92  	if v.limit == 0 {
    93  		// limit is zero means no limit.
    94  		v.rowCount = rowCount
    95  	} else {
    96  		v.rowCount = math.Min(rowCount, v.limit)
    97  	}
    98  	v.totalCost = v.rowCount * IndexCost
    99  }
   100  
   101  // EstimateCost estimates the cost of the plan.
   102  func EstimateCost(p Plan) float64 {
   103  	estimate(p)
   104  	return p.TotalCost()
   105  }