github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/stats.go (about) 1 // Copyright 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "github.com/matrixorigin/matrixone/pkg/pb/plan" 19 "math" 20 ) 21 22 func ReCalcNodeStats(nodeID int32, builder *QueryBuilder, recursive bool) { 23 node := builder.qry.Nodes[nodeID] 24 if recursive { 25 if len(node.Children) > 0 { 26 for _, child := range node.Children { 27 ReCalcNodeStats(child, builder, recursive) 28 } 29 } 30 } 31 32 var leftStats, rightStats, childStats *Stats 33 if len(node.Children) == 1 { 34 childStats = builder.qry.Nodes[node.Children[0]].Stats 35 } else if len(node.Children) == 2 { 36 leftStats = builder.qry.Nodes[node.Children[0]].Stats 37 rightStats = builder.qry.Nodes[node.Children[1]].Stats 38 } 39 40 switch node.NodeType { 41 case plan.Node_JOIN: 42 ndv := math.Min(leftStats.Outcnt, rightStats.Outcnt) 43 if ndv < 1 { 44 ndv = 1 45 } 46 switch node.JoinType { 47 case plan.Node_INNER: 48 outcnt := leftStats.Outcnt * rightStats.Outcnt / ndv 49 if len(node.OnList) > 0 { 50 outcnt *= 0.1 51 } 52 node.Stats = &plan.Stats{ 53 Outcnt: outcnt, 54 Cost: leftStats.Cost + rightStats.Cost, 55 HashmapSize: rightStats.Outcnt, 56 } 57 58 case plan.Node_LEFT: 59 outcnt := leftStats.Outcnt * rightStats.Outcnt / ndv 60 if len(node.OnList) > 0 { 61 outcnt *= 0.1 62 outcnt += leftStats.Outcnt 63 } 64 node.Stats = &plan.Stats{ 65 Outcnt: outcnt, 66 Cost: leftStats.Cost + rightStats.Cost, 67 HashmapSize: rightStats.Outcnt, 68 } 69 70 case plan.Node_RIGHT: 71 outcnt := leftStats.Outcnt * rightStats.Outcnt / ndv 72 if len(node.OnList) > 0 { 73 outcnt *= 0.1 74 outcnt += rightStats.Outcnt 75 } 76 node.Stats = &plan.Stats{ 77 Outcnt: outcnt, 78 Cost: leftStats.Cost + rightStats.Cost, 79 HashmapSize: rightStats.Outcnt, 80 } 81 82 case plan.Node_OUTER: 83 outcnt := leftStats.Outcnt * rightStats.Outcnt / ndv 84 if len(node.OnList) > 0 { 85 outcnt *= 0.1 86 outcnt += leftStats.Outcnt + rightStats.Outcnt 87 } 88 node.Stats = &plan.Stats{ 89 Outcnt: outcnt, 90 Cost: leftStats.Cost + rightStats.Cost, 91 HashmapSize: rightStats.Outcnt, 92 } 93 94 case plan.Node_SEMI, plan.Node_ANTI: 95 node.Stats = &plan.Stats{ 96 Outcnt: leftStats.Outcnt * .7, 97 Cost: leftStats.Cost + rightStats.Cost, 98 HashmapSize: rightStats.Outcnt, 99 } 100 101 case plan.Node_SINGLE, plan.Node_MARK: 102 node.Stats = &plan.Stats{ 103 Outcnt: leftStats.Outcnt, 104 Cost: leftStats.Cost + rightStats.Cost, 105 HashmapSize: rightStats.Outcnt, 106 } 107 } 108 109 case plan.Node_AGG: 110 if len(node.GroupBy) > 0 { 111 node.Stats = &plan.Stats{ 112 Outcnt: childStats.Outcnt * 0.1, 113 Cost: childStats.Outcnt, 114 HashmapSize: childStats.Outcnt, 115 } 116 } else { 117 node.Stats = &plan.Stats{ 118 Outcnt: 1, 119 Cost: childStats.Cost, 120 } 121 } 122 123 case plan.Node_UNION: 124 node.Stats = &plan.Stats{ 125 Outcnt: (leftStats.Outcnt + rightStats.Outcnt) * 0.7, 126 Cost: leftStats.Outcnt + rightStats.Outcnt, 127 HashmapSize: rightStats.Outcnt, 128 } 129 case plan.Node_UNION_ALL: 130 node.Stats = &plan.Stats{ 131 Outcnt: leftStats.Outcnt + rightStats.Outcnt, 132 Cost: leftStats.Outcnt + rightStats.Outcnt, 133 } 134 case plan.Node_INTERSECT: 135 node.Stats = &plan.Stats{ 136 Outcnt: math.Min(leftStats.Outcnt, rightStats.Outcnt) * 0.5, 137 Cost: leftStats.Outcnt + rightStats.Outcnt, 138 HashmapSize: rightStats.Outcnt, 139 } 140 case plan.Node_INTERSECT_ALL: 141 node.Stats = &plan.Stats{ 142 Outcnt: math.Min(leftStats.Outcnt, rightStats.Outcnt) * 0.7, 143 Cost: leftStats.Outcnt + rightStats.Outcnt, 144 HashmapSize: rightStats.Outcnt, 145 } 146 case plan.Node_MINUS: 147 minus := math.Max(leftStats.Outcnt, rightStats.Outcnt) - math.Min(leftStats.Outcnt, rightStats.Outcnt) 148 node.Stats = &plan.Stats{ 149 Outcnt: minus * 0.5, 150 Cost: leftStats.Outcnt + rightStats.Outcnt, 151 HashmapSize: rightStats.Outcnt, 152 } 153 case plan.Node_MINUS_ALL: 154 minus := math.Max(leftStats.Outcnt, rightStats.Outcnt) - math.Min(leftStats.Outcnt, rightStats.Outcnt) 155 node.Stats = &plan.Stats{ 156 Outcnt: minus * 0.7, 157 Cost: leftStats.Outcnt + rightStats.Outcnt, 158 HashmapSize: rightStats.Outcnt, 159 } 160 161 case plan.Node_TABLE_SCAN: 162 if node.ObjRef != nil { 163 node.Stats = builder.compCtx.Stats(node.ObjRef, HandleFiltersForZM(node.FilterList, builder.compCtx.GetProcess())) 164 } 165 166 default: 167 if len(node.Children) > 0 { 168 node.Stats = &plan.Stats{ 169 Outcnt: childStats.Outcnt, 170 Cost: childStats.Outcnt, 171 } 172 } else if node.Stats == nil { 173 node.Stats = &plan.Stats{ 174 Outcnt: 1000, 175 Cost: 1000000, 176 } 177 } 178 } 179 } 180 181 func DefaultStats() *plan.Stats { 182 stats := new(Stats) 183 stats.TableCnt = 1000 184 stats.Cost = 1000 185 stats.Outcnt = 1000 186 stats.Selectivity = 1 187 stats.BlockNum = 1 188 return stats 189 }