Skip to content

Commit

Permalink
add greedy option for large queries
Browse files Browse the repository at this point in the history
Signed-off-by: Andres Taylor <[email protected]>
  • Loading branch information
systay committed Dec 23, 2020
1 parent 713ea58 commit 44de903
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 50 deletions.
2 changes: 1 addition & 1 deletion go/vt/vtgate/planbuilder/querygraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (qg *queryGraph) addNoDepsPredicate(predicate sqlparser.Expr) {
}
}

func (qg *queryGraph) tryMerge(a, b joinTree, joinPredicates []sqlparser.Expr) joinTree {
func tryMerge(a, b joinTree, joinPredicates []sqlparser.Expr) joinTree {
aRoute, ok := a.(*routePlan)
if !ok {
return nil
Expand Down
78 changes: 68 additions & 10 deletions go/vt/vtgate/planbuilder/route_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ func newBuildSelectPlan(sel *sqlparser.Select, vschema ContextVSchema) (engine.P
return nil, err
}

tree, err := solve(qgraph, semTable, vschema)
var tree joinTree
if len(qgraph.tables) <= 10 {
tree, err = dpSolve(qgraph, semTable, vschema)
} else {
tree, err = greedySolve(qgraph, semTable, vschema)
}
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -218,7 +223,7 @@ func (jp *joinPlan) cost() int {
we use dynamic programming to find the cheapest route/join tree possible,
where the cost of a plan is the number of joins
*/
func solve(qg *queryGraph, semTable *semantics.SemTable, vschema ContextVSchema) (joinTree, error) {
func dpSolve(qg *queryGraph, semTable *semantics.SemTable, vschema ContextVSchema) (joinTree, error) {
size := len(qg.tables)
dpTable := makeDPTable()

Expand Down Expand Up @@ -251,14 +256,7 @@ func solve(qg *queryGraph, semTable *semantics.SemTable, vschema ContextVSchema)
continue
}
joinPredicates := qg.crossTable[solves]
newPlan := qg.tryMerge(lhs, rhs, joinPredicates)
if newPlan == nil {
newPlan = &joinPlan{
lhs: lhs,
rhs: rhs,
predicates: joinPredicates,
}
}
newPlan := createJoin(lhs, rhs, joinPredicates)
if oldPlan == nil || newPlan.cost() < oldPlan.cost() {
dpTable.add(newPlan)
}
Expand All @@ -269,6 +267,66 @@ func solve(qg *queryGraph, semTable *semantics.SemTable, vschema ContextVSchema)
return dpTable.planFor(allTables), nil
}

func createJoin(lhs joinTree, rhs joinTree, joinPredicates []sqlparser.Expr) joinTree {
newPlan := tryMerge(lhs, rhs, joinPredicates)
if newPlan == nil {
newPlan = &joinPlan{
lhs: lhs,
rhs: rhs,
predicates: joinPredicates,
}
}
return newPlan
}

/*
*/
func greedySolve(qg *queryGraph, semTable *semantics.SemTable, vschema ContextVSchema) (joinTree, error) {
plans := make([]joinTree, len(qg.tables))
planCache := map[semantics.TableSet]joinTree{}

// we start by seeding the table with the single routes
for i, table := range qg.tables {
solves := semTable.TableSetFor(table.alias)
plan, err := createRoutePlan(table, solves, vschema)
if err != nil {
return nil, err
}
plans[i] = plan
}

// loop while we have un-joined query parts left
for len(plans) > 1 {
var lIdx, rIdx int
var bestPlan joinTree
for i, lhs := range plans {
for j := i + 1; j < len(plans); j++ {
rhs := plans[j]
solves := lhs.solves() | rhs.solves()
joinPredicates := qg.crossTable[solves]
plan := planCache[solves]
if plan == nil {
plan = createJoin(lhs, rhs, joinPredicates)
planCache[solves] = plan
}

if bestPlan == nil || plan.cost() < bestPlan.cost() {
bestPlan = plan
// remember which plans we based on, so we can remove them later
lIdx = i
rIdx = j
}
}
}
plans = append(plans[:rIdx], plans[rIdx+1:]...)
plans = append(plans[:lIdx], plans[lIdx+1:]...)
plans = append(plans, bestPlan)
}

return plans[0], nil
}

func createRoutePlan(table *queryTable, solves semantics.TableSet, vschema ContextVSchema) (*routePlan, error) {
vschemaTable, _, _, _, _, err := vschema.FindTableOrVindex(table.table)
if err != nil {
Expand Down
40 changes: 1 addition & 39 deletions go/vt/vtgate/planbuilder/testdata/onecase.txt
Original file line number Diff line number Diff line change
@@ -1,39 +1 @@
# Add your test case here for debugging and run go test -run=One.
# ',' join
"select music.col from user, music"
{
"QueryType": "SELECT",
"Original": "select music.col from user, music",
"Instructions": {
"OperatorType": "Join",
"Variant": "Join",
"JoinColumnIndexes": "1",
"TableName": "user_music",
"Inputs": [
{
"OperatorType": "Route",
"Variant": "SelectScatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select 1 from user where 1 != 1",
"Query": "select 1 from user",
"Table": "user"
},
{
"OperatorType": "Route",
"Variant": "SelectScatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select music.col from music where 1 != 1",
"Query": "select music.col from music",
"Table": "music"
}
]
}
}
{
}
# Add your test case here for debugging and run go test -run=One.

0 comments on commit 44de903

Please sign in to comment.