@@ -104,22 +104,32 @@ func (s StaticStatistics) Cost(iterator Iterator) (Estimate, error) {
104104
105105 // Calculate CheckCost based on execution direction
106106 var checkCost int
107+ var iterResourcesCost int
108+ var iterSubjectsCost int
107109 switch it .direction {
108110 case leftToRight :
109111 // IterSubjects on left, then Check on right for each result
110112 checkCost = ls .IterSubjectsCost + (ls .Cardinality * rs .CheckCost )
113+ // IterResources on left, then IterResources on right for each result
114+ iterResourcesCost = ls .IterResourcesCost + (ls .Cardinality * rs .IterResourcesCost )
115+ // IterSubjects on left, then IterSubjects on right for each result
116+ iterSubjectsCost = ls .IterSubjectsCost + (ls .Cardinality * rs .IterSubjectsCost )
111117 case rightToLeft :
112118 // IterResources on right, then Check on left for each result
113119 checkCost = rs .IterResourcesCost + (rs .Cardinality * ls .CheckCost )
120+ // IterResources on right, then IterResources on left for each result
121+ iterResourcesCost = rs .IterResourcesCost + (rs .Cardinality * ls .IterResourcesCost )
122+ // IterSubjects on right, then IterSubjects on left for each result
123+ iterSubjectsCost = rs .IterSubjectsCost + (rs .Cardinality * ls .IterSubjectsCost )
114124 }
115125
116126 return Estimate {
117127 // Worst case, an arrow is the size of the cartesian product (full outer join) as we join the two subiterators.
118128 Cardinality : ls .Cardinality * rs .Cardinality ,
119129 CheckCost : checkCost ,
120130 CheckSelectivity : ls .CheckSelectivity * rs .CheckSelectivity ,
121- IterResourcesCost : ls . IterResourcesCost + ( ls . Cardinality * rs . IterResourcesCost ) ,
122- IterSubjectsCost : ls . IterSubjectsCost + ( ls . Cardinality * rs . IterSubjectsCost ) ,
131+ IterResourcesCost : iterResourcesCost ,
132+ IterSubjectsCost : iterSubjectsCost ,
123133 }, nil
124134 case * IntersectionArrow :
125135 ls , err := s .Cost (it .left )
@@ -133,11 +143,15 @@ func (s StaticStatistics) Cost(iterator Iterator) (Estimate, error) {
133143 // IntersectionArrow also does IterSubjects on left, then Check on right,
134144 // but only yields results when ALL subjects satisfy (more selective), estimated based on the fanout from IterSubjects
135145 selectivity := math .Pow (ls .CheckSelectivity , float64 (s .Fanout )) * rs .CheckSelectivity
146+ checkCost := ls .IterSubjectsCost + (ls .Cardinality * rs .CheckCost )
136147 return Estimate {
137- Cardinality : int (float64 (ls .Cardinality * rs .Cardinality ) * selectivity ),
138- CheckCost : ls .IterSubjectsCost + (ls .Cardinality * rs .CheckCost ),
139- CheckSelectivity : selectivity ,
140- IterResourcesCost : ls .IterResourcesCost + (ls .Cardinality * rs .IterResourcesCost ),
148+ Cardinality : int (float64 (ls .Cardinality * rs .Cardinality ) * selectivity ),
149+ CheckCost : checkCost ,
150+ CheckSelectivity : selectivity ,
151+ // We have to iterResources on both the left and the right side to get the potential
152+ // candidates, but we then need to check each of the candidates, so we pay an additional
153+ // check cost.
154+ IterResourcesCost : ls .IterResourcesCost + (ls .Cardinality * rs .IterResourcesCost ) + checkCost ,
141155 IterSubjectsCost : ls .IterSubjectsCost + (ls .Cardinality * rs .IterSubjectsCost ),
142156 }, nil
143157 case * Union :
0 commit comments