-
-
Couldn't load subscription status.
- Fork 239
Remove filters from LookupJoins when they're provably not required. #1888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3b54dbe
50ce792
48e8777
2b384a3
55b6b05
d4fba66
e26df6c
c0030d7
6fa77f6
52fdad0
f7f0426
8063b37
1c849f6
15654ac
d2a5654
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -196,7 +196,7 @@ func addLookupJoins(m *memo.Memo) error { | |
| for _, on := range conds { | ||
| filters := memo.SplitConjunction(on) | ||
| for _, idx := range indexes { | ||
| keyExprs, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(filters, extraFilters...)) | ||
| keyExprs, _, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(filters, extraFilters...)) | ||
| if keyExprs != nil { | ||
| concat = append(concat, &memo.Lookup{ | ||
| Index: idx, | ||
|
|
@@ -223,7 +223,7 @@ func addLookupJoins(m *memo.Memo) error { | |
| } | ||
|
|
||
| for _, idx := range indexes { | ||
| keyExprs, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(join.Filter, extraFilters...)) | ||
| keyExprs, matchedFilters, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(join.Filter, extraFilters...)) | ||
| if keyExprs == nil { | ||
| continue | ||
| } | ||
|
|
@@ -235,6 +235,19 @@ func addLookupJoins(m *memo.Memo) error { | |
| Nullmask: nullmask, | ||
| }, | ||
| } | ||
| var filters []memo.ScalarExpr | ||
| for _, filter := range rel.Filter { | ||
| found := false | ||
| for _, matchedFilter := range matchedFilters { | ||
| if filter == matchedFilter { | ||
| found = true | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can just do filters = append(filters, filter)
breakand get rid of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alternatively, could make matchedFilters a map, and avoid a nested for loop. Doubtful this will really make a difference in runtime. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The purpose behind the loop is to compute the set difference: we want to fill Something with a map would be asymptotically faster, but a nested loop is likely faster for all real uses cases. (You'd need a lot of filters in your join before the overhead of maintaining a map becomes worth it.) |
||
| } | ||
| } | ||
| if !found { | ||
| filters = append(filters, filter) | ||
| } | ||
| } | ||
| rel.Filter = filters | ||
| rel.Op = rel.Op.AsLookup() | ||
| rel.Lookup.Parent = rel.JoinBase | ||
| e.Group().Prepend(rel) | ||
|
|
@@ -246,30 +259,28 @@ func addLookupJoins(m *memo.Memo) error { | |
| // keyExprsForIndex returns a list of expression groups that compute a lookup | ||
| // key into the given index. The key fields will either be equality filters | ||
| // (from ON conditions) or constants. | ||
| func keyExprsForIndex(tableGrp memo.GroupId, idxExprs []sql.ColumnId, filters []memo.ScalarExpr) ([]memo.ScalarExpr, []bool) { | ||
| var keyExprs []memo.ScalarExpr | ||
| var nullmask []bool | ||
| func keyExprsForIndex(tableGrp memo.GroupId, idxExprs []sql.ColumnId, filters []memo.ScalarExpr) (keyExprs, matchedFilters []memo.ScalarExpr, nullmask []bool) { | ||
| for _, col := range idxExprs { | ||
| key, nullable := keyForExpr(col, tableGrp, filters) | ||
| key, filter, nullable := keyForExpr(col, tableGrp, filters) | ||
| if key == nil { | ||
| break | ||
| } | ||
| keyExprs = append(keyExprs, key) | ||
| matchedFilters = append(matchedFilters, filter) | ||
| nullmask = append(nullmask, nullable) | ||
| } | ||
| if len(keyExprs) == 0 { | ||
| return nil, nil | ||
| return nil, nil, nil | ||
| } | ||
| return keyExprs, nullmask | ||
| return keyExprs, matchedFilters, nullmask | ||
| } | ||
|
|
||
| // keyForExpr returns an equivalence or constant value to satisfy the | ||
| // lookup index expression. | ||
| func keyForExpr(targetCol sql.ColumnId, tableGrp memo.GroupId, filters []memo.ScalarExpr) (memo.ScalarExpr, bool) { | ||
| func keyForExpr(targetCol sql.ColumnId, tableGrp memo.GroupId, filters []memo.ScalarExpr) (key memo.ScalarExpr, filter memo.ScalarExpr, nullable bool) { | ||
| for _, f := range filters { | ||
| var left memo.ScalarExpr | ||
| var right memo.ScalarExpr | ||
| var nullable bool | ||
| switch e := f.Group().Scalar.(type) { | ||
| case *memo.Equal: | ||
| left = e.Left.Scalar | ||
|
|
@@ -280,7 +291,6 @@ func keyForExpr(targetCol sql.ColumnId, tableGrp memo.GroupId, filters []memo.Sc | |
| right = e.Right.Scalar | ||
| default: | ||
| } | ||
| var key memo.ScalarExpr | ||
| if ref, ok := left.(*memo.ColRef); ok && ref.Col == targetCol { | ||
| key = right | ||
| } else if ref, ok := right.(*memo.ColRef); ok && ref.Col == targetCol { | ||
|
|
@@ -291,10 +301,10 @@ func keyForExpr(targetCol sql.ColumnId, tableGrp memo.GroupId, filters []memo.Sc | |
| // expression key can be arbitrarily complex (or simple), but cannot | ||
| // reference the lookup table | ||
| if !key.Group().ScalarProps().Tables.Contains(int(memo.TableIdForSource(tableGrp))) { | ||
| return key, nullable | ||
| return key, f, nullable | ||
| } | ||
| } | ||
| return nil, false | ||
| return nil, nil, false | ||
| } | ||
|
|
||
| // convertSemiToInnerJoin adds inner join alternatives for semi joins. | ||
|
|
@@ -475,7 +485,7 @@ func addRightSemiJoins(m *memo.Memo) error { | |
| continue | ||
| } | ||
|
|
||
| keyExprs, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(semi.Filter, filters...)) | ||
| keyExprs, _, nullmask := keyExprsForIndex(tableGrp, idx.Cols(), append(semi.Filter, filters...)) | ||
| if keyExprs == nil { | ||
| continue | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you might be able to just match with
e.ExprId()There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! That's not only more efficient, but that allows us to detect matches through table aliases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switching to use e.ExprId() appears to have broken some correctness tests. I'm going to merge the previous version.