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 }