expression: constant propagation for outer join don't prop con… (#15855)

This commit is contained in:
Yiding Cui
2020-04-22 15:32:42 +08:00
committed by GitHub
parent d49573e050
commit 0f2dbcdca4
3 changed files with 27 additions and 6 deletions

View File

@ -119,7 +119,7 @@ func validEqualCond(ctx sessionctx.Context, cond Expression) (*Column, *Constant
// for 'a, b, a < 3', it returns 'true, false, b < 3'
// for 'a, b, sin(a) + cos(a) = 5', it returns 'true, false, returns sin(b) + cos(b) = 5'
// for 'a, b, cast(a) < rand()', it returns 'false, true, cast(a) < rand()'
func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Expression) (bool, bool, Expression) {
func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Expression, rejectControl bool) (bool, bool, Expression) {
sf, ok := cond.(*ScalarFunction)
if !ok {
return false, false, cond
@ -132,6 +132,13 @@ func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Exp
if _, ok := inequalFunctions[sf.FuncName.L]; ok {
return false, true, cond
}
// See https://github.com/pingcap/tidb/issues/15782. The control function's result may rely on the original nullable
// information of the outer side column. Its args cannot be replaced easily.
// A more strict check is that after we replace the arg. We check the nullability of the new expression.
// But we haven't maintained it yet, so don't replace the arg of the control function currently.
if rejectControl && (sf.FuncName.L == ast.Ifnull || sf.FuncName.L == ast.If || sf.FuncName.L == ast.Case) {
return false, false, cond
}
for idx, expr := range sf.GetArgs() {
if src.Equal(nil, expr) {
_, coll, _ := cond.CharsetAndCollation(ctx)
@ -145,7 +152,7 @@ func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Exp
}
args[idx] = tgt
} else {
subReplaced, isNonDeterministic, subExpr := tryToReplaceCond(ctx, src, tgt, expr)
subReplaced, isNonDeterministic, subExpr := tryToReplaceCond(ctx, src, tgt, expr, rejectControl)
if isNonDeterministic {
return false, true, cond
} else if subReplaced {
@ -244,11 +251,11 @@ func (s *propConstSolver) propagateColumnEQ() {
continue
}
cond := s.conditions[k]
replaced, _, newExpr := tryToReplaceCond(s.ctx, coli, colj, cond)
replaced, _, newExpr := tryToReplaceCond(s.ctx, coli, colj, cond, false)
if replaced {
s.conditions = append(s.conditions, newExpr)
}
replaced, _, newExpr = tryToReplaceCond(s.ctx, colj, coli, cond)
replaced, _, newExpr = tryToReplaceCond(s.ctx, colj, coli, cond, false)
if replaced {
s.conditions = append(s.conditions, newExpr)
}
@ -498,7 +505,7 @@ func (s *propOuterJoinConstSolver) deriveConds(outerCol, innerCol *Column, schem
visited[k+offset] = true
continue
}
replaced, _, newExpr := tryToReplaceCond(s.ctx, outerCol, innerCol, cond)
replaced, _, newExpr := tryToReplaceCond(s.ctx, outerCol, innerCol, cond, true)
if replaced {
s.joinConds = append(s.joinConds, newExpr)
}

View File

@ -33,7 +33,9 @@
"explain select * from t1 left join t2 on t1.a = 1 or (t1.a = 2 and t1.a = 3)",
"explain select * from t1 left join t2 on true where t1.a = 1 or (t1.a = 2 and t1.a = 3)",
// Constant propagation over left outer semi join, filter with aux column should not be derived.
"explain select * from t1 where t1.b > 1 or t1.b in (select b from t2)"
"explain select * from t1 where t1.b > 1 or t1.b in (select b from t2)",
// Don't propagate for the control function.
"explain select * from t1 left join t2 on t1.a = t2.a where ifnull(t2.b, t1.a) = 1"
]
}
]

View File

@ -274,6 +274,18 @@
" └─TableReader_11(Probe) 10000.00 root data:TableFullScan_10",
" └─TableFullScan_10 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
]
},
{
"SQL": "explain select * from t1 left join t2 on t1.a = t2.a where ifnull(t2.b, t1.a) = 1",
"Result": [
"Selection_7 9990.00 root eq(ifnull(test.t2.b, test.t1.a), 1)",
"└─HashJoin_8 12487.50 root left outer join, equal:[eq(test.t1.a, test.t2.a)]",
" ├─TableReader_14(Build) 9990.00 root data:Selection_13",
" │ └─Selection_13 9990.00 cop[tikv] not(isnull(test.t2.a))",
" │ └─TableFullScan_12 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
" └─TableReader_11(Probe) 10000.00 root data:TableFullScan_10",
" └─TableFullScan_10 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
]
}
]
}