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

*: implement index nested loop join #2945

Merged
merged 53 commits into from
Apr 1, 2017
Merged

*: implement index nested loop join #2945

merged 53 commits into from
Apr 1, 2017

Conversation

winoros
Copy link
Member

@winoros winoros commented Mar 28, 2017

When one of join's children is a scan and there are equal conditions that use the index of this scan. We can build this join to a nested loop join and build this scan using index to look up.
Currently index nested loop join is controlled by the hint /*+ TIDB_INLJ(t1, t2) */ not cost-based.
And only the table in TIDB_INLJ() will be considered as outer table of the join.

@@ -571,6 +571,205 @@ func (p *Join) convert2PhysicalPlanRight(prop *requiredProperty, innerJoin bool)
return resultInfo, nil
}

// buildSelectionWithConds will build a selection use the conditions of join and convert one side's column to correlated column.
// This is called when build nested loop join.
func (p *Join) buildSelectionWithConds(left bool) (*Selection, []*expression.CorrelatedColumn) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left is not a good name.

selection.SetSchema(innerChild.Schema().Clone())
selection.SetChildren(innerChild)
if left {
conds = make([]expression.Expression, 0, len(p.EqualConditions)+len(p.RightConditions)+len(p.OtherConditions))
Copy link
Member

@hanfei1991 hanfei1991 Mar 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to resolve again for other condition? add test for it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

ap := &PhysicalApply{
PhysicalJoin: resultInfo.p,
OuterSchema: corCols,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ap.self = ap

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But self is one part of baseLogicalPlan not one part of basePlan.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well

join.tp = "NestedLoopJoinLeft"
join.allocator = p.allocator
join.initIDAndContext(p.ctx)
join.SetChildren(lInfo.p, rInfo.p)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

join.self = join

@hanfei1991
Copy link
Member

Can we offer a way to choose the outer table of index join ?

@winoros
Copy link
Member Author

winoros commented Mar 31, 2017

Now we can use hint to choose the outer table.

@hanfei1991
Copy link
Member

LGTM

@hanfei1991 hanfei1991 added the status/LGT1 Indicates that a PR has LGTM 1. label Mar 31, 2017
@winoros
Copy link
Member Author

winoros commented Mar 31, 2017

PTAL @coocood @shenli

tk.MustQuery("select /*+ TIDB_INLJ(t, t1) */ * from t right outer join t1 on t.a=t1.a").Check(testkit.Rows("1 1 1 2", "1 1 1 3", "3 3 3 4", "<nil> <nil> 4 5"))
tk.MustQuery("select /*+ TIDB_INLJ(t, t1) */ avg(t.b) from t right outer join t1 on t.a=t1.a").Check(testkit.Rows("1.6667"))

_, err = tk.Exec("select /*+ TIDB_INLJ(t) TIDB_SMJ(t) * from t join t1 on t.a=t1.a")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntax error.

@@ -1004,7 +1246,7 @@ func (p *Union) convert2PhysicalPlan(prop *requiredProperty) (*physicalPlanInfo,
// makeScanController will try to build a selection that controls the below scan's filter condition,
// and return a physicalPlanInfo. If the onlyJudge is true, it will only check whether this selection
// can become a scan controller without building the physical plan.
func (p *Selection) makeScanController(onlyJudge bool) (*physicalPlanInfo, bool) {
func (p *Selection) makeScanController(onlyJudge bool) (*physicalPlanInfo, int) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace judge with check.

}
ts := &PhysicalTableScan{
cond, _ := expression.SubstituteCorCol2Constant(expr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the condition already been substituted at the beginning of the function?

}
ts := &PhysicalTableScan{
// else will judge whether can build a index scan or just build a index scan.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Search the keyword judge replace them all, include comments.

colMapper: make(map[*ast.ColumnNameExpr]int),
is: is,
}
p := builder.build(stmt)
Copy link
Member

@hanfei1991 hanfei1991 Mar 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

combine the line 1129 to 1142 as doOptimize to avoid the Cache plan.

better = better || (chosenPlan.accessEqualCount == is.accessEqualCount && chosenPlan.accessInAndEqCount < is.accessInAndEqCount)
_, _, accessEqualCount, accessInAndEqCount := DetachIndexScanConditions(condsBackUp, idx)
better := chosenPlan == nil || bestEqualCount < accessEqualCount
better = better || (bestEqualCount == accessEqualCount && bestInAndEqCount < accessInAndEqCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think simply check access equal count is enough.
better := accessEqualCount >= bestEqualCount
Other wise, we need to add tests for accesInAndEqCount.

Copy link
Member

@coocood coocood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@coocood coocood merged commit aaa6184 into master Apr 1, 2017
@coocood coocood deleted the yiding/inlj_2 branch April 1, 2017 07:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/LGT1 Indicates that a PR has LGTM 1.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants