Skip to content
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

planner: open the new only_full_group_by check #7

Merged
merged 28 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5e0afbe
planner: open the new only_full_group_by check
winoros Mar 2, 2022
1a2839e
refine the open only-full-group-check
AilinKid Mar 4, 2022
25570e3
make fmt
AilinKid Mar 4, 2022
6474f2f
make fmt
AilinKid Mar 4, 2022
1c5053f
make fmt
AilinKid Mar 6, 2022
486f99c
Merge branch 'master' into fd-open-check
winoros Mar 7, 2022
5bb98ea
inital fds's map for tableDual
AilinKid Mar 7, 2022
197b9e3
Merge remote-tracking branch 'yiding/fd-open-check' into fd-open-check
winoros Mar 7, 2022
603b8ec
Merge branch 'functional-dependency' into fd-open-check
winoros Mar 7, 2022
5dea823
fix create view should report only full group by error
AilinKid Mar 7, 2022
7ba8d74
fix outer projection wrongly utilize subquery/view's agg flag
AilinKid Mar 8, 2022
3e86bbb
planner: fix the fd check for non-deterministic func and any_value
winoros Mar 8, 2022
025afb9
fix join miss merging of the not-null-cols and registered map
AilinKid Mar 8, 2022
d476e40
inject the FD for generated columns in datasource
AilinKid Mar 8, 2022
f589165
test case 6, add more tests
AilinKid Mar 8, 2022
5df67ab
distinguish unique lax FD and non-unique lax FD
AilinKid Mar 8, 2022
b543e6f
todo: eval-not-null func refuse NOT wrapper
AilinKid Mar 9, 2022
248cf04
use allCons to extract constant and equivalence FD for inner join
AilinKid Mar 9, 2022
f244b5c
left join can extend left pk to all cols
AilinKid Mar 9, 2022
f4213c8
refine the error message
AilinKid Mar 9, 2022
7d4d37e
compute the complete closure of a FD before project cols
AilinKid Mar 10, 2022
20bd3d6
compute the new derived FD for left join, named as 3.3.1
AilinKid Mar 10, 2022
de1d49f
build equivalence from subquery's projected correlated-col to outer b…
AilinKid Mar 12, 2022
21c2eea
Update only_full_group_by_test.go
AilinKid Mar 12, 2022
46a0ab8
planner: add the cases when left join is cartesian product
winoros Mar 13, 2022
feb2ce4
Merge branch 'functional-dependency' into fd-open-check
winoros Mar 13, 2022
bd92c87
fix selection above left join / fix col can be nullable after outer j…
AilinKid Mar 14, 2022
4c56b17
fix selection above left join with constant
AilinKid Mar 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions planner/core/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ func (p *LogicalJoin) extractFDForOuterJoin() *fd.FDSet {

filterFD := &fd.FDSet{HashCodeToUniqueID: make(map[string]int)}

constUniqueIDs := extractConstantCols(eqCondSlice, p.SCtx(), filterFD)
constUniqueIDs := extractConstantCols(allConds, p.SCtx(), filterFD)

equivUniqueIDs := extractEquivalenceCols(eqCondSlice, p.SCtx(), filterFD)
equivUniqueIDs := extractEquivalenceCols(allConds, p.SCtx(), filterFD)

filterFD.AddConstants(constUniqueIDs)
for _, equiv := range equivUniqueIDs {
Expand Down
41 changes: 38 additions & 3 deletions planner/functional_dependency/fd_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ func (s *FDSet) MakeApply(inner *FDSet) {
//
// above all: constant FD are lost
//
// <3> equivalence FD: let's see equivalence FD as double-directed strict FD from join equal conditions, and we only keep the
// <3.1> equivalence FD: let's see equivalence FD as double-directed strict FD from join equal conditions, and we only keep the
// rhs ~~> lhs.
// a b | c d e
// ------+----------------
Expand All @@ -613,12 +613,34 @@ func (s *FDSet) MakeApply(inner *FDSet) {
// because two same determinant key {1} can point to different dependency {1} & {NULL}. But in return, FD like {c} -> {a}
// are degraded to the corresponding lax one.
//
// <3.2> equivalence FD: when the determinant and dependencies from a equivalence FD of join condition are each covering a strict
// FD of the left / right side. The left side strict FD's dependencies can be extended to all cols after join result.
// a b | c d e
// ------+----------------
// 1 1 | 1 NULL 1
// 2 2 | NULL NULL NULL
// 3 1 | NULL NULL NULL
// left join with (a,b) * (c,d,e) on (a=c and b=1). Supposing that left `a` are strict Key and right `c` are strict Key too.
// Key means the strict FD can determine all cols from that table.
// case 1: left join matched
// one left row match one / multi rows from right side, since `c` is strict determine all cols from right table, so
// {a} == {b} --> {all cols in right}, according to the transitive rule of strict FD, we get {a} --> {all cols in right}
// case 2: left join miss match
// miss matched rows from left side are unique originally, even appended with NULL value from right side, they are still
// strictly determine themselves and even the all rows after left join.
// conclusion combined:
// equivalence with both strict Key from right and left, the left side's strict FD can be extended to all rows after left join.
//
// 4: the new formed FD {left key, right key} -> {all columns} are preserved in spite of the null-supplied rows.
//
func (s *FDSet) MakeOuterJoin(innerFDs, filterFDs *FDSet, outerCols, innerCols FastIntSet) {
// copy down the left PK and right PK before the s has changed for later usage.
leftPK, ok1 := s.FindPrimaryKey()
rightPK, ok2 := innerFDs.FindPrimaryKey()
copyLeftFDSet := &FDSet{}
copyLeftFDSet.AddFrom(s)
AilinKid marked this conversation as resolved.
Show resolved Hide resolved
copyRightFDSet := &FDSet{}
copyRightFDSet.AddFrom(innerFDs)

for _, edge := range innerFDs.fdEdges {
// Rule #2.2, constant FD are removed from right side of left join.
Expand Down Expand Up @@ -657,9 +679,22 @@ func (s *FDSet) MakeOuterJoin(innerFDs, filterFDs *FDSet, outerCols, innerCols F
// Rule #3.3, we only keep the lax FD from right side pointing the left side.
if edge.equiv {
// equivalence: {superset} --> {superset}, either `from` or `to` side is ok here.
laxFDFrom := edge.from.Intersection(innerCols)
laxFDTo := edge.from.Intersection(outerCols)
// Rule 3.3.2
equivColsRight := edge.from.Intersection(innerCols)
equivColsLeft := edge.from.Intersection(outerCols)
rightAllCols := copyRightFDSet.AllCols()
leftAllCols := copyLeftFDSet.AllCols()
coveringStrictKeyRight := rightAllCols.SubsetOf(copyRightFDSet.ClosureOfStrict(equivColsRight))
coveringStrictKeyLeft := leftAllCols.SubsetOf(copyLeftFDSet.closureOfStrict(equivColsLeft))
if coveringStrictKeyLeft && coveringStrictKeyRight {
// find the minimum strict Key set, and add
s.addFunctionalDependency(copyLeftFDSet.ReduceCols(equivColsLeft), rightAllCols.Union(leftAllCols), true, false, false)
}

// Rule 3.3.1
// need to break down the superset of equivalence, adding each lax FD of them.
laxFDFrom := equivColsRight
laxFDTo := equivColsLeft
for i, ok := laxFDFrom.Next(0); ok; i, ok = laxFDFrom.Next(i + 1) {
for j, ok := laxFDTo.Next(0); ok; j, ok = laxFDTo.Next(j + 1) {
s.addFunctionalDependency(NewFastIntSet(i), NewFastIntSet(j), false, false, true)
Expand Down
4 changes: 4 additions & 0 deletions planner/functional_dependency/only_full_group_by_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,8 @@ func TestOnlyFullGroupByOldCases(t *testing.T) {
tk.MustExec("CREATE algorithm=merge definer='root'@'localhost' VIEW customer as SELECT pk,a,b FROM customer1 JOIN customer2 USING (pk);")
tk.MustQuery("select customer.pk, customer.b from customer group by customer.pk;")
tk.MustQuery("select customer1.a, count(*) from customer1 left join customer2 on customer1.a=customer2.b where customer2.pk in (7,9) group by customer2.b;")
tk.MustExec("drop view if exists customer")
// this left join can extend left pk to all cols.
tk.MustExec("CREATE algorithm=merge definer='root'@'localhost' VIEW customer as SELECT pk,a,b FROM customer1 LEFT JOIN customer2 USING (pk);")
tk.MustQuery("select customer.pk, customer.b from customer group by customer.pk;")
}