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

plan: change the logic of converting to index join #7553

Merged
merged 10 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
14 changes: 14 additions & 0 deletions expression/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,17 @@ func (s *exprStack) push(expr Expression) {
func (s *exprStack) len() int {
return len(s.stack)
}

// ColumnSliceIsIntersect checks whether two column slice is intersected.
func ColumnSliceIsIntersect(s1, s2 []*Column) bool {
intSet := map[int64]struct{}{}
for _, col := range s1 {
intSet[col.UniqueID] = struct{}{}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

UniqueID is changed to int64 in #7385, should modify the map definition here.

for _, col := range s2 {
if _, ok := intSet[col.UniqueID]; ok {
return true
}
}
return false
}
28 changes: 20 additions & 8 deletions plan/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ func (p *LogicalJoin) buildRangeForIndexJoin(indexInfo *model.IndexInfo, innerPl
return nil, nil, nil
}

conds, eqConds, keyOff2IdxOff := p.buildFakeEqCondsForIndexJoin(innerJoinKeys, idxCols, colLengths, innerPlan)
access, eqConds, remained, keyOff2IdxOff := p.buildFakeEqCondsForIndexJoin(innerJoinKeys, idxCols, colLengths, innerPlan.pushedDownConds)

if len(keyOff2IdxOff) == 0 {
return nil, nil, nil
Expand All @@ -527,7 +527,7 @@ func (p *LogicalJoin) buildRangeForIndexJoin(indexInfo *model.IndexInfo, innerPl
// After constant propagation, there won'be cases that t1.a=t2.a and t2.a=1 occur in the same time.
Copy link
Member

Choose a reason for hiding this comment

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

do we need to update this comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

updated

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems it was not updated.

// And if there're cases like t1.a=t2.a and t1.a > 1, we can also guarantee that t1.a > 1 won't be chosen as access condition.
// So DetachCondAndBuildRangeForIndex won't miss the equal conditions we generate.
ranges, accesses, remained, _, err := ranger.DetachCondAndBuildRangeForIndex(p.ctx, conds, idxCols, colLengths)
ranges, accesses, moreRemained, _, err := ranger.DetachCondAndBuildRangeForIndex(p.ctx, access, idxCols, colLengths)
if err != nil {
terror.Log(errors.Trace(err))
return nil, nil, nil
Expand All @@ -540,36 +540,48 @@ func (p *LogicalJoin) buildRangeForIndexJoin(indexInfo *model.IndexInfo, innerPl
}
Copy link
Contributor

Choose a reason for hiding this comment

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

when will expression.Contains(accesses, eqCond) be false

Copy link
Member Author

Choose a reason for hiding this comment

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

t1.a=t2.a and t1.c=t2.c, and index (t1.a, t1.b, t1.c). This case currently won't use index join.

}

return ranges, remained, keyOff2IdxOff
return ranges, append(remained, moreRemained...), keyOff2IdxOff
}

func (p *LogicalJoin) buildFakeEqCondsForIndexJoin(keys, idxCols []*expression.Column, colLengths []int,
innerPlan *DataSource) (accesses, eqConds []expression.Expression, keyOff2IdxOff []int) {
innerFilters []expression.Expression) (accesses, eqConds, remained []expression.Expression, keyOff2IdxOff []int) {
// Check whether all join keys match one column from index.
keyOff2IdxOff = joinKeysMatchIndex(keys, idxCols, colLengths)
if keyOff2IdxOff == nil {
return nil, nil, nil
return nil, nil, nil, nil
}

usableKeys := make([]*expression.Column, 0, len(keys))

// After predicate push down, the one side conditions of join must be the conditions that cannot be pushed down and
// cannot calculate range either. So we only need the innerPlan.pushedDownConds and the eq conditions that we generate.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment should be updated, no innerPlan now.

// TODO: There may be a selection that block the index join.
conds := make([]expression.Expression, 0, len(keys)+len(innerPlan.pushedDownConds))
conds := make([]expression.Expression, 0, len(keys)+len(innerFilters))
eqConds = make([]expression.Expression, 0, len(keys))
// Construct a fake equal expression for calculating the range.
for i, key := range keys {
if keyOff2IdxOff[i] < 0 {
continue
}
usableKeys = append(usableKeys, key)
// Int datum 1 can convert to all column's type(numeric type, string type, json, time type, enum, set) safely.
fakeConstant := &expression.Constant{Value: types.NewIntDatum(1), RetType: key.GetType()}
eqFunc := expression.NewFunctionInternal(p.ctx, ast.EQ, types.NewFieldType(mysql.TypeTiny), key, fakeConstant)
conds = append(conds, eqFunc)
eqConds = append(eqConds, eqFunc)
}

conds = append(conds, innerPlan.pushedDownConds...)
return conds, eqConds, keyOff2IdxOff
remained = make([]expression.Expression, 0, len(innerFilters))
Copy link
Contributor

Choose a reason for hiding this comment

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

We may need a comment for this code block.

for _, filter := range innerFilters {
affectedCols := expression.ExtractColumns(filter)
if expression.ColumnSliceIsIntersect(affectedCols, usableKeys) {
remained = append(remained, filter)
continue
}
conds = append(conds, filter)
Copy link
Member

Choose a reason for hiding this comment

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

Since this filter doesn't contain the column of join keys, can we just move all the filters in innerFilters to remained?

Copy link
Member Author

Choose a reason for hiding this comment

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

t1.a=t2.a and t1.b=1 index is (a, b).

Copy link
Member

Choose a reason for hiding this comment

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

got it.

}

return conds, eqConds, remained, keyOff2IdxOff
}

// tryToGetIndexJoin will get index join by hints. If we can generate a valid index join by hint, the second return value
Expand Down
4 changes: 4 additions & 0 deletions plan/physical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ func (s *testPlanSuite) TestDAGPlanBuilderJoin(c *C) {
sql: "select /*+ TIDB_INLJ(t1) */ * from t t1 join t t2 where t1.f=t2.f and t1.a=t2.a",
best: "IndexJoin{TableReader(Table(t))->TableReader(Table(t))}(t1.a,t2.a)",
},
{
sql: "select /*+ TIDB_INLJ(t1) */ * from t t1 join t t2 where t1.a=t2.a and t2.a in (1, 2)",
best: "IndexJoin{TableReader(Table(t))->TableReader(Table(t)->Sel([in(t2.a, 1, 2)]))}(t1.a,t2.a)",
},
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like this test sql would not trigger the code path of this patch, i.e, getIndexJoinByOuterIdx -> buildRangeForIndexJoin, because column a is handle, it would follow getIndexJoinByOuterIdx -> constructInnerTableScan. Should we change the column a in the sql to column b instead? or am I missing anything?

}
for i, tt := range tests {
comment := Commentf("case:%v sql:%s", i, tt.sql)
Expand Down