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  }