func (no *NaiveOptimizer) TrySortMerge(plan planner.Plan) { last, curr := planner.FindNextPipelineComponentOfType(plan.Root.GetSource(), planner.JoinerType) if curr != nil { currJoiner := curr.(planner.Joiner) sortMergeJoiner := planner.NewOttoSortMergeJoiner() err := sortMergeJoiner.SetCondition(currJoiner.GetCondition()) if err == nil { // now we need to make sure that the upstream sources can be sorted propertly leftSource := currJoiner.GetLeftSource() rightSource := currJoiner.GetRightSource() // FIXME for now this only works if the immidiate sources are datasources // needs to be made to work through joins and other pipeline components leftDataSource, isLeftDataSource := leftSource.(planner.DataSource) rightDataSource, isRightDataSource := rightSource.(planner.DataSource) if isLeftDataSource && isRightDataSource { if leftDataSource.GetOrderBy() == nil && rightDataSource.GetOrderBy() == nil { leftSort := parser.NewSortItem(parser.NewProperty(sortMergeJoiner.LeftExpr.SymbolsReferenced()[0]), true) err = leftDataSource.SetOrderBy(parser.SortList{*leftSort}) if err != nil { //log.Printf("merge join not possible left datasource rejected order by") return } rightSort := parser.NewSortItem(parser.NewProperty(sortMergeJoiner.RightExpr.SymbolsReferenced()[0]), true) err = rightDataSource.SetOrderBy(parser.SortList{*rightSort}) if err != nil { //log.Printf("merge join not possible right datasource rejected order by") return } //if we made it this far, it shoudl work //lets attach the left and right datasources to the new joiner sortMergeJoiner.SetLeftSource(leftDataSource) sortMergeJoiner.SetRightSource(rightDataSource) //now we just need to replace the existing joiner with the new one if last == nil { plan.Root.SetSource(sortMergeJoiner) } else { last.SetSource(sortMergeJoiner) } } else { //log.Printf("merge join optimization only supports direct datasources that are not already ordered") } } else { //log.Printf("merge join optimization only supports direct datasources before join") } } else { //log.Printf("merge join not going to work here %v", err) } } }
func (no *NaiveOptimizer) MoveJoinConditionsUpTree(plan planner.Plan) { _, curr := planner.FindNextPipelineComponentOfType(plan.Root.GetSource(), planner.JoinerType) if curr != nil { currJoiner := curr.(planner.Joiner) //log.Printf("Expression considerered for separation is %#v", currJoiner.GetCondition()) // we need to keep running this until it sep is nil joinCondition := currJoiner.GetCondition() if joinCondition != nil { sep, rest := LookForSeparableExpression(joinCondition) for sep != nil { //log.Printf("Sep Expression is %v", sep) //log.Printf("Rest Expression is %v", rest) // now try to place the separable expression sepSymbols := sep.SymbolsReferenced() if len(sepSymbols) > 0 { sepDataSource := sepSymbols[0] sepDotIndex := strings.Index(sepDataSource, ".") sepDs := sepDataSource[0:sepDotIndex] // find the datasource on the LHS _, leftDs := planner.FindNextPipelineComponentOfType(currJoiner.GetLeftSource(), planner.DataSourceType) if leftDs != nil { leftDataSource := leftDs.(planner.DataSource) if leftDataSource.GetAs() == sepDs { //log.Printf("this expression goes left") moved := MoveSeparableExpressionToDataSource(leftDataSource, currJoiner, sep, rest) if !moved { // as soon as we get to something we couldnt move, we stop trying return } } } // find the datasource on the RHS _, rightDs := planner.FindNextPipelineComponentOfType(currJoiner.GetRightSource(), planner.DataSourceType) if rightDs != nil { rightDataSource := rightDs.(planner.DataSource) if rightDataSource.GetAs() == sepDs { //log.Printf("this expression goes right") moved := MoveSeparableExpressionToDataSource(rightDataSource, currJoiner, sep, rest) if !moved { // as soon as we get to something we couldnt move, we stop trying return } } } } joinCondition = currJoiner.GetCondition() sep, rest = LookForSeparableExpression(joinCondition) } } } }