plan: fix failed case when do index nested loop join (#3034)
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user