plan: fix failed case when do index nested loop join (#3034)

This commit is contained in:
Yiding Cui
2017-04-13 14:25:24 +08:00
committed by GitHub
parent d5f049abd5
commit a671b3c5e5
3 changed files with 59 additions and 16 deletions

View File

@ -546,6 +546,7 @@ func (p *LogicalJoin) convert2PhysicalPlanRight(prop *requiredProperty, innerJoi
}
// buildSelectionWithConds will build a selection use the conditions of join and convert one side's column to correlated column.
// If the inner side is one selection then one data source, the inner child should be the data source other than the selection.
// This is called when build nested loop join.
func (p *LogicalJoin) buildSelectionWithConds(leftAsOuter bool) (*Selection, []*expression.CorrelatedColumn) {
var (
@ -562,6 +563,10 @@ func (p *LogicalJoin) buildSelectionWithConds(leftAsOuter bool) (*Selection, []*
innerConditions = p.LeftConditions
innerChild = p.children[0]
}
if sel, ok := innerChild.(*Selection); ok {
innerConditions = append(innerConditions, sel.Conditions...)
innerChild = sel.children[0]
}
corCols := make([]*expression.CorrelatedColumn, 0, outerSchema.Len())
for _, col := range outerSchema.Columns {
corCol := &expression.CorrelatedColumn{Column: *col, Data: new(types.Datum)}
@ -572,26 +577,38 @@ func (p *LogicalJoin) buildSelectionWithConds(leftAsOuter bool) (*Selection, []*
selection.SetSchema(innerChild.Schema().Clone())
selection.SetChildren(innerChild)
conds := make([]expression.Expression, 0, len(p.EqualConditions)+len(innerConditions)+len(p.OtherConditions))
for _, cond := range innerConditions {
conds = append(conds, cond)
}
for _, cond := range p.EqualConditions {
newCond := expression.ConvertCol2CorCol(cond, corCols, outerSchema)
conds = append(conds, newCond)
}
selection.Conditions = conds
// Currently only eq conds will be considered when we call checkScanController, and innerConds from the below sel may contain correlated column,
// which will have side effect when we do check. So we do check before append other conditions into selection.
selection.controllerStatus = selection.checkScanController()
if selection.controllerStatus == notController {
return nil, nil
}
for _, cond := range innerConditions {
conds = append(conds, cond)
}
for _, cond := range p.OtherConditions {
newCond := expression.ConvertCol2CorCol(cond, corCols, outerSchema)
newCond.ResolveIndices(innerChild.Schema())
conds = append(conds, newCond)
}
selection.Conditions = conds
selection.controllerStatus = selection.checkScanController()
return selection, corCols
}
func (p *LogicalJoin) convert2IndexNestedLoopJoinLeft(prop *requiredProperty, innerJoin bool) (*physicalPlanInfo, error) {
lChild := p.children[0].(LogicalPlan)
if _, ok := p.children[1].(*DataSource); !ok {
switch x := p.children[1].(type) {
case *DataSource:
case *Selection:
if _, ok := x.children[0].(*DataSource); !ok {
return nil, nil
}
default:
return nil, nil
}
allLeft := true
@ -620,7 +637,7 @@ func (p *LogicalJoin) convert2IndexNestedLoopJoinLeft(prop *requiredProperty, in
return nil, nil
}
selection, corCols := p.buildSelectionWithConds(true)
if selection.controllerStatus == notController {
if selection == nil {
return nil, nil
}
rInfo := selection.makeScanController()
@ -656,7 +673,13 @@ func (p *LogicalJoin) convert2IndexNestedLoopJoinLeft(prop *requiredProperty, in
func (p *LogicalJoin) convert2IndexNestedLoopJoinRight(prop *requiredProperty, innerJoin bool) (*physicalPlanInfo, error) {
rChild := p.children[1].(LogicalPlan)
if _, ok := p.children[0].(*DataSource); !ok {
switch x := p.children[0].(type) {
case *DataSource:
case *Selection:
if _, ok := x.children[0].(*DataSource); !ok {
return nil, nil
}
default:
return nil, nil
}
allRight := true
@ -685,7 +708,7 @@ func (p *LogicalJoin) convert2IndexNestedLoopJoinRight(prop *requiredProperty, i
return nil, nil
}
selection, corCols := p.buildSelectionWithConds(false)
if selection.controllerStatus == notController {
if selection == nil {
return nil, nil
}
lInfo := selection.makeScanController()
@ -960,7 +983,7 @@ func (p *LogicalJoin) convert2PhysicalPlan(prop *requiredProperty) (*physicalPla
break
}
if p.preferINLJ > 0 && p.hasEqualConds() {
if _, ok := p.children[1].(*DataSource); ok && (p.preferINLJ&preferLeftAsOuter) > 0 {
if (p.preferINLJ & preferLeftAsOuter) > 0 {
lNLJInfo, err := p.convert2IndexNestedLoopJoinLeft(prop, true)
if err != nil {
return nil, errors.Trace(err)
@ -969,7 +992,7 @@ func (p *LogicalJoin) convert2PhysicalPlan(prop *requiredProperty) (*physicalPla
info = lNLJInfo
}
}
if _, ok := p.children[0].(*DataSource); ok && (p.preferINLJ&preferRightAsOuter) > 0 {
if (p.preferINLJ & preferRightAsOuter) > 0 {
rNLJInfo, err := p.convert2IndexNestedLoopJoinRight(prop, true)
if err != nil {
return nil, errors.Trace(err)

View File

@ -1112,6 +1112,18 @@ func (s *testPlanSuite) TestJoinAlgorithm(c *C) {
sql: "select /*+ tidb_inlj(t2) */ * from t t1 join t t2 on t1.c=t2.c and t1.d=t2.d and t1.e > t2.e",
ans: "Apply{Index(t.c_d_e)[]->Selection->Table(t)}",
},
{
sql: "select /*+ TIDB_INLJ(t1) */ * from t join t t1 where t.a=t1.a and t.b > 100 and t1.b>10",
ans: "Apply{Table(t)->Selection->Table(t)}",
},
{
sql: "select /*+ TIDB_INLJ(tt, t1) */ * from (select * from t where t.b > 100) tt left join t t1 on tt.a=t1.a and t1.b>10",
ans: "Apply{Table(t)->Table(t)->Selection}",
},
{
sql: "select /*+ TIDB_INLJ(t, t1) */ * from t left join (select * from t where t.b > 10) t1 on t.a=t1.a and t.b > 100",
ans: "LeftHashJoin{Table(t)->Table(t)}(test.t.a,t1.a)",
},
}
for _, ca := range cases {
comment := Commentf("for %s", ca.sql)

View File

@ -696,16 +696,24 @@ func (p *PhysicalApply) MarshalJSON() ([]byte, error) {
return nil, errors.Trace(err)
}
buffer := bytes.NewBufferString("{")
if p.PhysicalJoin.(*PhysicalHashJoin).SmallTable == 1 {
switch x := p.PhysicalJoin.(type) {
case *PhysicalHashJoin:
if x.SmallTable == 1 {
buffer.WriteString(fmt.Sprintf(
"\"innerPlan\": \"%s\",\n "+
"\"outerPlan\": \"%s\",\n "+
"\"join\": %s\n}", p.children[1].ID(), p.children[0].ID(), join))
} else {
buffer.WriteString(fmt.Sprintf(
"\"innerPlan\": \"%s\",\n "+
"\"outerPlan\": \"%s\",\n "+
"\"join\": %s\n}", p.children[0].ID(), p.children[1].ID(), join))
}
case *PhysicalHashSemiJoin:
buffer.WriteString(fmt.Sprintf(
"\"innerPlan\": \"%s\",\n "+
"\"outerPlan\": \"%s\",\n "+
"\"join\": %s\n}", p.children[1].ID(), p.children[0].ID(), join))
} else {
buffer.WriteString(fmt.Sprintf(
"\"innerPlan\": \"%s\",\n "+
"\"outerPlan\": \"%s\",\n "+
"\"join\": %s\n}", p.children[0].ID(), p.children[1].ID(), join))
}
return buffer.Bytes(), nil
}