@@ -118,7 +118,7 @@ func (n *joinNodeLeaf) Optimize(ctx impls.OptimizationContext) {
118118 n .relation .Optimize (ctx )
119119}
120120
121- func (n * joinNodeLeaf ) EstimateCost () plan. Cost {
121+ func (n * joinNodeLeaf ) EstimateCost () impls. NodeCost {
122122 return n .relation .EstimateCost ()
123123}
124124
@@ -187,8 +187,34 @@ func (n *joinNodeInternal) Optimize(ctx impls.OptimizationContext) {
187187 n .strategy = & logicalNestedLoopJoinStrategy {n : n }
188188}
189189
190- func (n * joinNodeInternal ) EstimateCost () plan.Cost {
191- return plan.Cost {} // TODO
190+ var joinMergeCostPerRow = impls.ResourceCost {CPU : 0.2 }
191+ var joinFilterCostPerRow = impls.ResourceCost {CPU : 0.1 }
192+
193+ func (n * joinNodeInternal ) EstimateCost () impls.NodeCost {
194+ // TODO - the following estimates are based on nested loop joins
195+
196+ leftCost := n .left .EstimateCost ()
197+ rightCost := n .right .EstimateCost ()
198+
199+ selectivity := 1.0 // TODO - estimate selectivity based on filter
200+ numLeftRows := leftCost .EstimatedRows
201+ numCandidateRows := leftCost .EstimatedRows * rightCost .EstimatedRows
202+ estimatedRows := int (float64 (numCandidateRows ) * selectivity )
203+
204+ // For each left row we scan, we reset the right relation scanner
205+ costPerLeftRow := impls .SumCosts (leftCost .VariableCost , rightCost .FixedCost )
206+
207+ // For each candidate row we scan, we evaluate the join condition
208+ costPerCandidateRow := impls .SumCosts (rightCost .VariableCost , joinMergeCostPerRow , joinFilterCostPerRow )
209+
210+ return impls.NodeCost {
211+ EstimatedRows : estimatedRows ,
212+ FixedCost : leftCost .FixedCost ,
213+ VariableCost : impls .SumCosts (
214+ costPerLeftRow .ScaleUniform (float64 (numLeftRows )),
215+ costPerCandidateRow .ScaleUniform (float64 (numCandidateRows )),
216+ ),
217+ }
192218}
193219
194220func (n * joinNodeInternal ) Filter () impls.Expression {
0 commit comments