Skip to content

Commit

Permalink
planner: add new logical rule for constant propagation (#46544)
Browse files Browse the repository at this point in the history
close #15082
  • Loading branch information
elsa0520 authored Sep 11, 2023
1 parent e9ef984 commit 02ceded
Show file tree
Hide file tree
Showing 18 changed files with 887 additions and 92 deletions.
46 changes: 23 additions & 23 deletions cmd/explaintest/r/explain_cte.result
Original file line number Diff line number Diff line change
Expand Up @@ -511,17 +511,17 @@ a b
explain insert into t1 select t1.a, t1.b from t1 inner join (select t2.c from t2 inner join (with temp as (select e from t3 where t3.f = 1234) select e from temp) tt on t2.d = tt.e) t on t1.a = t.c;
id estRows task access object operator info
Insert_1 N/A root N/A
└─HashJoin_25 15.61 root inner join, equal:[eq(explain_cte.t2.c, explain_cte.t1.a)]
├─HashJoin_27(Build) 12.49 root inner join, equal:[eq(explain_cte.t3.e, explain_cte.t2.d)]
│ ├─TableReader_30(Build) 9.99 root data:Selection_29
│ │ └─Selection_29 9.99 cop[tikv] eq(explain_cte.t3.f, 1234), not(isnull(explain_cte.t3.e))
│ │ └─TableFullScan_28 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo
│ └─TableReader_33(Probe) 9980.01 root data:Selection_32
│ └─Selection_32 9980.01 cop[tikv] not(isnull(explain_cte.t2.c)), not(isnull(explain_cte.t2.d))
│ └─TableFullScan_31 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_36(Probe) 9990.00 root data:Selection_35
└─Selection_35 9990.00 cop[tikv] not(isnull(explain_cte.t1.a))
└─TableFullScan_34 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
└─HashJoin_26 15.61 root inner join, equal:[eq(explain_cte.t2.c, explain_cte.t1.a)]
├─HashJoin_28(Build) 12.49 root inner join, equal:[eq(explain_cte.t3.e, explain_cte.t2.d)]
│ ├─TableReader_31(Build) 9.99 root data:Selection_30
│ │ └─Selection_30 9.99 cop[tikv] eq(explain_cte.t3.f, 1234), not(isnull(explain_cte.t3.e))
│ │ └─TableFullScan_29 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo
│ └─TableReader_34(Probe) 9980.01 root data:Selection_33
│ └─Selection_33 9980.01 cop[tikv] not(isnull(explain_cte.t2.c)), not(isnull(explain_cte.t2.d))
│ └─TableFullScan_32 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_37(Probe) 9990.00 root data:Selection_36
└─Selection_36 9990.00 cop[tikv] not(isnull(explain_cte.t1.a))
└─TableFullScan_35 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
insert into t1 select t1.a, t1.b from t1 inner join (select t2.c from t2 inner join (with temp as (select e from t3 where t3.f = 1234) select e from temp) tt on t2.d = tt.e) t on t1.a = t.c;
select * from t1;
a b
Expand All @@ -530,18 +530,18 @@ a b
explain delete from t1 using t1 inner join (select t2.c from t2 inner join (with temp as (select e from t3 where t3.f = 1234) select e from temp) tt on t2.d = tt.e) t on t1.a = t.c;
id estRows task access object operator info
Delete_17 N/A root N/A
└─Projection_22 15.61 root explain_cte.t1.a, explain_cte.t1.b, explain_cte.t1._tidb_rowid, explain_cte.t2.c
└─HashJoin_24 15.61 root inner join, equal:[eq(explain_cte.t2.c, explain_cte.t1.a)]
├─HashJoin_26(Build) 12.49 root inner join, equal:[eq(explain_cte.t3.e, explain_cte.t2.d)]
│ ├─TableReader_29(Build) 9.99 root data:Selection_28
│ │ └─Selection_28 9.99 cop[tikv] eq(explain_cte.t3.f, 1234), not(isnull(explain_cte.t3.e))
│ │ └─TableFullScan_27 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo
│ └─TableReader_32(Probe) 9980.01 root data:Selection_31
│ └─Selection_31 9980.01 cop[tikv] not(isnull(explain_cte.t2.c)), not(isnull(explain_cte.t2.d))
│ └─TableFullScan_30 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_35(Probe) 9990.00 root data:Selection_34
└─Selection_34 9990.00 cop[tikv] not(isnull(explain_cte.t1.a))
└─TableFullScan_33 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
└─Projection_23 15.61 root explain_cte.t1.a, explain_cte.t1.b, explain_cte.t1._tidb_rowid, explain_cte.t2.c
└─HashJoin_25 15.61 root inner join, equal:[eq(explain_cte.t2.c, explain_cte.t1.a)]
├─HashJoin_27(Build) 12.49 root inner join, equal:[eq(explain_cte.t3.e, explain_cte.t2.d)]
│ ├─TableReader_30(Build) 9.99 root data:Selection_29
│ │ └─Selection_29 9.99 cop[tikv] eq(explain_cte.t3.f, 1234), not(isnull(explain_cte.t3.e))
│ │ └─TableFullScan_28 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo
│ └─TableReader_33(Probe) 9980.01 root data:Selection_32
│ └─Selection_32 9980.01 cop[tikv] not(isnull(explain_cte.t2.c)), not(isnull(explain_cte.t2.d))
│ └─TableFullScan_31 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_36(Probe) 9990.00 root data:Selection_35
└─Selection_35 9990.00 cop[tikv] not(isnull(explain_cte.t1.a))
└─TableFullScan_34 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
delete from t1 using t1 inner join (select t2.c from t2 inner join (with temp as (select e from t3 where t3.f = 1234) select e from temp) tt on t2.d = tt.e) t on t1.a = t.c;
select * from t1;
a b
21 changes: 10 additions & 11 deletions executor/index_advise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,22 @@ and b.txn_accno = a.new_accno;`
rows := [][]interface{}{
{"Update_8"},
{"└─IndexJoin_14"},
{" ├─TableReader_25(Build)"},
{" │ └─Selection_24"},
{" │ └─TableFullScan_23"},
{" ├─TableReader_23(Build)"},
{" │ └─Selection_22"},
{" │ └─TableFullScan_21"},
{" └─IndexReader_12(Probe)"},
{" └─Selection_11"},
{" └─IndexRangeScan_10"},
{" └─IndexRangeScan_11"},
}
tk.MustExec("set @@session.tidb_enable_inl_join_inner_multi_pattern='ON'")
tk.MustQuery("explain "+sql).CheckAt([]int{0}, rows)
rows = [][]interface{}{
{"Update_8"},
{"└─HashJoin_10"},
{" ├─IndexReader_17(Build)"},
{" │ └─IndexRangeScan_16"},
{" └─TableReader_14(Probe)"},
{" └─Selection_13"},
{" └─TableFullScan_12"},
{"└─HashJoin_12"},
{" ├─TableReader_15(Build)"},
{" │ └─Selection_14"},
{" │ └─TableFullScan_13"},
{" └─IndexReader_18(Probe)"},
{" └─IndexRangeScan_17"},
}
tk.MustExec("set @@session.tidb_enable_inl_join_inner_multi_pattern='OFF'")
tk.MustQuery("explain "+sql).CheckAt([]int{0}, rows)
Expand Down
14 changes: 8 additions & 6 deletions expression/constant_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ func (s *basePropConstSolver) tryToUpdateEQList(col *Column, con *Constant) (boo
return true, false
}

func validEqualCondHelper(ctx sessionctx.Context, eq *ScalarFunction, colIsLeft bool) (*Column, *Constant) {
// ValidCompareConstantPredicateHelper checks if the predicate is a compare constant predicate, like "Column xxx Constant"
func ValidCompareConstantPredicateHelper(eq *ScalarFunction, colIsLeft bool) (*Column, *Constant) {
var col *Column
var con *Constant
colOk := false
Expand Down Expand Up @@ -97,14 +98,14 @@ func validEqualCondHelper(ctx sessionctx.Context, eq *ScalarFunction, colIsLeft
}

// validEqualCond checks if the cond is an expression like [column eq constant].
func validEqualCond(ctx sessionctx.Context, cond Expression) (*Column, *Constant) {
func validEqualCond(cond Expression) (*Column, *Constant) {
if eq, ok := cond.(*ScalarFunction); ok {
if eq.FuncName.L != ast.EQ {
return nil, nil
}
col, con := validEqualCondHelper(ctx, eq, true)
col, con := ValidCompareConstantPredicateHelper(eq, true)
if col == nil {
return validEqualCondHelper(ctx, eq, false)
return ValidCompareConstantPredicateHelper(eq, false)
}
return col, con
}
Expand Down Expand Up @@ -296,7 +297,7 @@ func (s *propConstSolver) pickNewEQConds(visited []bool) (retMapper map[int]*Con
if visited[i] {
continue
}
col, con := validEqualCond(s.ctx, cond)
col, con := validEqualCond(cond)
// Then we check if this CNF item is a false constant. If so, we will set the whole condition to false.
var ok bool
if col == nil {
Expand Down Expand Up @@ -357,6 +358,7 @@ func (s *propConstSolver) solve(conditions []Expression) []Expression {
}

// PropagateConstant propagate constant values of deterministic predicates in a condition.
// This is a constant propagation logic for expression list such as ['a=1', 'a=b']
func PropagateConstant(ctx sessionctx.Context, conditions []Expression) []Expression {
return newPropConstSolver().PropagateConstant(ctx, conditions)
}
Expand Down Expand Up @@ -400,7 +402,7 @@ func (s *propOuterJoinConstSolver) pickEQCondsOnOuterCol(retMapper map[int]*Cons
if visited[i+condsOffset] {
continue
}
col, con := validEqualCond(s.ctx, cond)
col, con := validEqualCond(cond)
// Then we check if this CNF item is a false constant. If so, we will set the whole condition to false.
var ok bool
if col == nil {
Expand Down
48 changes: 22 additions & 26 deletions planner/cardinality/selectivity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1202,33 +1202,29 @@ func TestIndexJoinInnerRowCountUpperBound(t *testing.T) {
stat := h.GetTableStats(tblInfo)
stat.HistColl = mockStatsTbl.HistColl

query := "explain format = 'brief' " +
"select /*+ inl_join(t2) */ * from (select * from t where t.a < 1) as t1 join t t2 where t2.a = 0 and t1.a = t2.b"

testKit.MustQuery(query).Check(testkit.Rows(
"IndexJoin 1000000.00 root inner join, inner:IndexLookUp, outer key:test.t.a, inner key:test.t.b, equal cond:eq(test.t.a, test.t.b)",
"├─TableReader(Build) 1000.00 root data:Selection",
"│ └─Selection 1000.00 cop[tikv] lt(test.t.a, 1), not(isnull(test.t.a))",
"│ └─TableFullScan 500000.00 cop[tikv] table:t keep order:false, stats:pseudo",
"└─IndexLookUp(Probe) 1000000.00 root ",
" ├─Selection(Build) 500000000.00 cop[tikv] not(isnull(test.t.b))",
" │ └─IndexRangeScan 500000000.00 cop[tikv] table:t2, index:idx(b) range: decided by [eq(test.t.b, test.t.a)], keep order:false, stats:pseudo",
" └─Selection(Probe) 1000000.00 cop[tikv] eq(test.t.a, 0)",
" └─TableRowIDScan 500000000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
))
var (
input []string
output []struct {
Query string
Result []string
}
)

testKit.MustExec("set @@tidb_opt_fix_control = '44855:ON'")
testKit.MustQuery(query).Check(testkit.Rows(
"IndexJoin 1000000.00 root inner join, inner:IndexLookUp, outer key:test.t.a, inner key:test.t.b, equal cond:eq(test.t.a, test.t.b)",
"├─TableReader(Build) 1000.00 root data:Selection",
"│ └─Selection 1000.00 cop[tikv] lt(test.t.a, 1), not(isnull(test.t.a))",
"│ └─TableFullScan 500000.00 cop[tikv] table:t keep order:false, stats:pseudo",
"└─IndexLookUp(Probe) 1000000.00 root ",
" ├─Selection(Build) 1000000.00 cop[tikv] not(isnull(test.t.b))",
" │ └─IndexRangeScan 1000000.00 cop[tikv] table:t2, index:idx(b) range: decided by [eq(test.t.b, test.t.a)], keep order:false, stats:pseudo",
" └─Selection(Probe) 1000000.00 cop[tikv] eq(test.t.a, 0)",
" └─TableRowIDScan 1000000.00 cop[tikv] table:t2 keep order:false, stats:pseudo",
))
suiteData := cardinality.GetCardinalitySuiteData()
suiteData.LoadTestCases(t, &input, &output)
for i := 0; i < len(input); i++ {
testdata.OnRecord(func() {
output[i].Query = input[i]
})
if !strings.HasPrefix(input[i], "explain") {
testKit.MustExec(input[i])
continue
}
testdata.OnRecord(func() {
output[i].Result = testdata.ConvertRowsToStrings(testKit.MustQuery(input[i]).Rows())
})
testKit.MustQuery(input[i]).Check(testkit.Rows(output[i].Result...))
}
}

func TestOrderingIdxSelectivityThreshold(t *testing.T) {
Expand Down
8 changes: 8 additions & 0 deletions planner/cardinality/testdata/cardinality_suite_in.json
Original file line number Diff line number Diff line change
Expand Up @@ -454,5 +454,13 @@
"select * from t where a = 100 and b = 350",
"select * from t where a < -1500 and b > 400 and b < 403"
]
},
{
"name": "TestIndexJoinInnerRowCountUpperBound",
"cases": [
"explain format = 'brief' select /*+ inl_join(t2) */ * from (select * from t where t.a < 1) as t1 join t t2 where t2.a = 0 and t1.a = t2.b",
"set @@tidb_opt_fix_control = '44855:ON'",
"explain format = 'brief' select /*+ inl_join(t2) */ * from (select * from t where t.a < 1) as t1 join t t2 where t2.a = 0 and t1.a = t2.b"
]
}
]
39 changes: 39 additions & 0 deletions planner/cardinality/testdata/cardinality_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -4630,5 +4630,44 @@
]
}
]
},
{
"Name": "TestIndexJoinInnerRowCountUpperBound",
"Cases": [
{
"Query": "explain format = 'brief' select /*+ inl_join(t2) */ * from (select * from t where t.a < 1) as t1 join t t2 where t2.a = 0 and t1.a = t2.b",
"Result": [
"Projection 2000.00 root test.t.a, test.t.b, test.t.a, test.t.b",
"└─IndexJoin 2000.00 root inner join, inner:IndexLookUp, outer key:test.t.a, inner key:test.t.b, equal cond:eq(test.t.a, test.t.b)",
" ├─TableReader(Build) 1000.00 root data:Selection",
" │ └─Selection 1000.00 cop[tikv] lt(test.t.a, 1), not(isnull(test.t.a))",
" │ └─TableFullScan 500000.00 cop[tikv] table:t keep order:false, stats:pseudo",
" └─IndexLookUp(Probe) 2000.00 root ",
" ├─Selection(Build) 1000000.00 cop[tikv] lt(test.t.b, 1), not(isnull(test.t.b))",
" │ └─IndexRangeScan 500000000.00 cop[tikv] table:t2, index:idx(b) range: decided by [eq(test.t.b, test.t.a)], keep order:false, stats:pseudo",
" └─Selection(Probe) 2000.00 cop[tikv] eq(test.t.a, 0)",
" └─TableRowIDScan 1000000.00 cop[tikv] table:t2 keep order:false, stats:pseudo"
]
},
{
"Query": "set @@tidb_opt_fix_control = '44855:ON'",
"Result": null
},
{
"Query": "explain format = 'brief' select /*+ inl_join(t2) */ * from (select * from t where t.a < 1) as t1 join t t2 where t2.a = 0 and t1.a = t2.b",
"Result": [
"Projection 2000.00 root test.t.a, test.t.b, test.t.a, test.t.b",
"└─IndexJoin 2000.00 root inner join, inner:IndexLookUp, outer key:test.t.a, inner key:test.t.b, equal cond:eq(test.t.a, test.t.b)",
" ├─TableReader(Build) 1000.00 root data:Selection",
" │ └─Selection 1000.00 cop[tikv] lt(test.t.a, 1), not(isnull(test.t.a))",
" │ └─TableFullScan 500000.00 cop[tikv] table:t keep order:false, stats:pseudo",
" └─IndexLookUp(Probe) 2000.00 root ",
" ├─Selection(Build) 1000000.00 cop[tikv] lt(test.t.b, 1), not(isnull(test.t.b))",
" │ └─IndexRangeScan 1000000.00 cop[tikv] table:t2, index:idx(b) range: decided by [eq(test.t.b, test.t.a)], keep order:false, stats:pseudo",
" └─Selection(Probe) 2000.00 cop[tikv] eq(test.t.a, 0)",
" └─TableRowIDScan 1000000.00 cop[tikv] table:t2 keep order:false, stats:pseudo"
]
}
]
}
]
2 changes: 2 additions & 0 deletions planner/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ go_library(
"rule_aggregation_skew_rewrite.go",
"rule_build_key_info.go",
"rule_column_pruning.go",
"rule_constant_propagation.go",
"rule_decorrelate.go",
"rule_derive_topn_from_window.go",
"rule_eliminate_projection.go",
Expand Down Expand Up @@ -221,6 +222,7 @@ go_test(
"planbuilder_test.go",
"point_get_plan_test.go",
"preprocess_test.go",
"rule_constant_propagation_test.go",
"rule_generate_column_substitute_test.go",
"rule_join_reorder_dp_test.go",
"rule_join_reorder_test.go",
Expand Down
Loading

0 comments on commit 02ceded

Please sign in to comment.