diff --git a/executor/benchmark_test.go b/executor/benchmark_test.go index b041ceead54b3..f12dd7dd5784f 100644 --- a/executor/benchmark_test.go +++ b/executor/benchmark_test.go @@ -230,8 +230,8 @@ func buildMockDataSourceWithIndex(opt mockDataSourceParameters, index []int) *mo return buildMockDataSource(opt) } +// aggTestCase has a fixed schema (aggCol Double, groupBy LongLong). type aggTestCase struct { - // The test table's schema is fixed (aggCol Double, groupBy LongLong). execType string // "hash" or "stream" aggFunc string // sum, avg, count .... groupByNDV int // the number of distinct group-by keys @@ -505,8 +505,8 @@ func buildWindowExecutor(ctx sessionctx.Context, windowFunc string, funcs int, f return exec } +// windowTestCase has a fixed schema (col Double, partitionBy LongLong, rawData VarString(16), col LongLong). type windowTestCase struct { - // The test table's schema is fixed (col Double, partitionBy LongLong, rawData VarString(16), col LongLong). windowFunc string numFunc int // The number of windowFuncs. Default: 1. frame *core.WindowFrame @@ -1341,12 +1341,28 @@ func BenchmarkIndexJoinExec(b *testing.B) { type mergeJoinTestCase struct { indexJoinTestCase + childrenUsedSchema [][]bool } func prepare4MergeJoin(tc *mergeJoinTestCase, leftExec, rightExec *mockDataSource) *MergeJoinExec { outerCols, innerCols := tc.columns(), tc.columns() - joinSchema := expression.NewSchema(outerCols...) - joinSchema.Append(innerCols...) + + joinSchema := expression.NewSchema() + if tc.childrenUsedSchema != nil { + for i, used := range tc.childrenUsedSchema[0] { + if used { + joinSchema.Append(outerCols[i]) + } + } + for i, used := range tc.childrenUsedSchema[1] { + if used { + joinSchema.Append(innerCols[i]) + } + } + } else { + joinSchema.Append(outerCols...) + joinSchema.Append(innerCols...) + } outerJoinKeys := make([]*expression.Column, 0, len(tc.outerJoinKeyIdx)) innerJoinKeys := make([]*expression.Column, 0, len(tc.innerJoinKeyIdx)) @@ -1370,19 +1386,20 @@ func prepare4MergeJoin(tc *mergeJoinTestCase, leftExec, rightExec *mockDataSourc stmtCtx: tc.ctx.GetSessionVars().StmtCtx, baseExecutor: newBaseExecutor(tc.ctx, joinSchema, stringutil.StringerStr("MergeJoin"), leftExec, rightExec), compareFuncs: compareFuncs, - joiner: newJoiner( - tc.ctx, - 0, - false, - defaultValues, - nil, - retTypes(leftExec), - retTypes(rightExec), - nil, - ), - isOuterJoin: false, + isOuterJoin: false, } + e.joiner = newJoiner( + tc.ctx, + 0, + false, + defaultValues, + nil, + retTypes(leftExec), + retTypes(rightExec), + tc.childrenUsedSchema, + ) + e.innerTable = &mergeJoinTable{ isInner: true, childIndex: 1, @@ -1399,7 +1416,7 @@ func prepare4MergeJoin(tc *mergeJoinTestCase, leftExec, rightExec *mockDataSourc } func defaultMergeJoinTestCase() *mergeJoinTestCase { - return &mergeJoinTestCase{*defaultIndexJoinTestCase()} + return &mergeJoinTestCase{*defaultIndexJoinTestCase(), nil} } func newMergeJoinBenchmark(numOuterRows, numInnerDup, numInnerRedundant int) (tc *mergeJoinTestCase, innerDS, outerDS *mockDataSource) { @@ -1421,7 +1438,7 @@ func newMergeJoinBenchmark(numOuterRows, numInnerDup, numInnerRedundant int) (tc innerIdx: []int{0, 1}, rawData: wideString, } - tc = &mergeJoinTestCase{*itc} + tc = &mergeJoinTestCase{*itc, nil} outerOpt := mockDataSourceParameters{ schema: expression.NewSchema(tc.columns()...), rows: numOuterRows, @@ -1514,37 +1531,35 @@ func BenchmarkMergeJoinExec(b *testing.B) { totalRows := 300000 - { - numInnerDup := 1 - tc, innerDS, outerDS := newMergeJoinBenchmark(totalRows/numInnerDup, numInnerDup, 0) - b.Run(fmt.Sprintf("merge join %v", tc), func(b *testing.B) { - benchmarkMergeJoinExecWithCase(b, tc, outerDS, innerDS, innerMergeJoin) - }) + innerDupAndRedundant := [][]int{ + {1, 0}, + {100, 0}, + {10000, 0}, + {1, 30000}, } - { - numInnerDup := 100 - tc, innerDS, outerDS := newMergeJoinBenchmark(totalRows/numInnerDup, numInnerDup, 0) - b.Run(fmt.Sprintf("merge join %v", tc), func(b *testing.B) { - benchmarkMergeJoinExecWithCase(b, tc, outerDS, innerDS, innerMergeJoin) - }) + childrenUsedSchemas := [][][]bool{ + nil, + { + {true, false, false}, + {false, true, false}, + }, } - { - numInnerDup := 10000 - tc, innerDS, outerDS := newMergeJoinBenchmark(totalRows/numInnerDup, numInnerDup, 0) - b.Run(fmt.Sprintf("merge join %v", tc), func(b *testing.B) { - benchmarkMergeJoinExecWithCase(b, tc, outerDS, innerDS, innerMergeJoin) - }) - } + for _, params := range innerDupAndRedundant { + numInnerDup, numInnerRedundant := params[0], params[1] + for _, childrenUsedSchema := range childrenUsedSchemas { + tc, innerDS, outerDS := newMergeJoinBenchmark(totalRows/numInnerDup, numInnerDup, numInnerRedundant) + inlineProj := false + if childrenUsedSchema != nil { + inlineProj = true + tc.childrenUsedSchema = childrenUsedSchema + } - { - numInnerDup := 1 - numInnerRedundant := 30000 - tc, innerDS, outerDS := newMergeJoinBenchmark(totalRows/numInnerDup, numInnerDup, numInnerRedundant) - b.Run(fmt.Sprintf("merge join %v", tc), func(b *testing.B) { - benchmarkMergeJoinExecWithCase(b, tc, outerDS, innerDS, innerMergeJoin) - }) + b.Run(fmt.Sprintf("merge join %v InlineProj:%v", tc, inlineProj), func(b *testing.B) { + benchmarkMergeJoinExecWithCase(b, tc, outerDS, innerDS, innerMergeJoin) + }) + } } } diff --git a/executor/builder.go b/executor/builder.go index 9a85ef36917f0..7a5c1edc975a2 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -1005,7 +1005,7 @@ func (b *executorBuilder) buildMergeJoin(v *plannercore.PhysicalMergeJoin) Execu v.OtherConditions, retTypes(leftExec), retTypes(rightExec), - nil, + markChildrenUsedCols(v.Schema(), v.Children()[0].Schema(), v.Children()[1].Schema()), ), isOuterJoin: v.JoinType.IsOuterJoin(), desc: v.Desc, diff --git a/executor/executor_required_rows_test.go b/executor/executor_required_rows_test.go index 56527396346a9..4709192299c7a 100644 --- a/executor/executor_required_rows_test.go +++ b/executor/executor_required_rows_test.go @@ -855,6 +855,10 @@ func (mp *mockPlan) GetExecutor() Executor { return mp.exec } +func (mp *mockPlan) Schema() *expression.Schema { + return mp.exec.Schema() +} + func (s *testExecSuite) TestVecGroupCheckerDATARACE(c *C) { ctx := mock.NewContext() diff --git a/executor/merge_join_test.go b/executor/merge_join_test.go index 08448b5ee1b23..507403125b4fc 100644 --- a/executor/merge_join_test.go +++ b/executor/merge_join_test.go @@ -387,12 +387,11 @@ func (s *testSuite2) TestMergeJoin(c *C) { tk.MustExec("create table s(a int, b int)") tk.MustExec("insert into s values(1,1)") tk.MustQuery("explain select /*+ TIDB_SMJ(t, s) */ a in (select a from s where s.b >= t.b) from t").Check(testkit.Rows( - "Projection_7 10000.00 root Column#7", - "└─MergeJoin_8 10000.00 root left outer semi join, other cond:eq(test.t.a, test.s.a), ge(test.s.b, test.t.b)", - " ├─TableReader_12(Build) 10000.00 root data:TableFullScan_11", - " │ └─TableFullScan_11 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", - " └─TableReader_10(Probe) 10000.00 root data:TableFullScan_9", - " └─TableFullScan_9 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + "MergeJoin_8 10000.00 root left outer semi join, other cond:eq(test.t.a, test.s.a), ge(test.s.b, test.t.b)", + "├─TableReader_12(Build) 10000.00 root data:TableFullScan_11", + "│ └─TableFullScan_11 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", + "└─TableReader_10(Probe) 10000.00 root data:TableFullScan_9", + " └─TableFullScan_9 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", )) tk.MustQuery("select /*+ TIDB_SMJ(t, s) */ a in (select a from s where s.b >= t.b) from t").Check(testkit.Rows( "1", @@ -420,16 +419,15 @@ func (s *testSuite2) TestMergeJoin(c *C) { tk.MustExec("create table s (a int)") tk.MustExec("insert into s values (4), (1), (3), (2)") tk.MustQuery("explain select s1.a1 from (select a as a1 from s order by s.a desc) as s1 join (select a as a2 from s order by s.a desc) as s2 on s1.a1 = s2.a2 order by s1.a1 desc").Check(testkit.Rows( - "Projection_27 12487.50 root test.s.a", - "└─MergeJoin_28 12487.50 root inner join, left key:test.s.a, right key:test.s.a", - " ├─Sort_31(Build) 9990.00 root test.s.a:desc", - " │ └─TableReader_26 9990.00 root data:Selection_25", - " │ └─Selection_25 9990.00 cop[tikv] not(isnull(test.s.a))", - " │ └─TableFullScan_24 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", - " └─Sort_29(Probe) 9990.00 root test.s.a:desc", - " └─TableReader_21 9990.00 root data:Selection_20", - " └─Selection_20 9990.00 cop[tikv] not(isnull(test.s.a))", - " └─TableFullScan_19 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", + "MergeJoin_28 12487.50 root inner join, left key:test.s.a, right key:test.s.a", + "├─Sort_31(Build) 9990.00 root test.s.a:desc", + "│ └─TableReader_26 9990.00 root data:Selection_25", + "│ └─Selection_25 9990.00 cop[tikv] not(isnull(test.s.a))", + "│ └─TableFullScan_24 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", + "└─Sort_29(Probe) 9990.00 root test.s.a:desc", + " └─TableReader_21 9990.00 root data:Selection_20", + " └─Selection_20 9990.00 cop[tikv] not(isnull(test.s.a))", + " └─TableFullScan_19 10000.00 cop[tikv] table:s keep order:false, stats:pseudo", )) tk.MustQuery("select s1.a1 from (select a as a1 from s order by s.a desc) as s1 join (select a as a2 from s order by s.a desc) as s2 on s1.a1 = s2.a2 order by s1.a1 desc").Check(testkit.Rows( "4", "3", "2", "1")) diff --git a/planner/cascades/testdata/integration_suite_in.json b/planner/cascades/testdata/integration_suite_in.json index 547c2cee8e486..4a19d038c02ab 100644 --- a/planner/cascades/testdata/integration_suite_in.json +++ b/planner/cascades/testdata/integration_suite_in.json @@ -152,7 +152,8 @@ "select 1 from (select /*+ HASH_JOIN(t1) */ t1.a not in (select t2.a from t2) from t1) x;", // TODO: should use hash join "select /*+ INL_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", "select /*+ INL_HASH_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", - "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;" + "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", + "select /*+ MERGE_JOIN(t1, t2) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;" ] } ] diff --git a/planner/cascades/testdata/integration_suite_out.json b/planner/cascades/testdata/integration_suite_out.json index 28155a0a22cc0..1aa1d2aada3ca 100644 --- a/planner/cascades/testdata/integration_suite_out.json +++ b/planner/cascades/testdata/integration_suite_out.json @@ -1281,6 +1281,19 @@ "Result": [ "1 1" ] + }, + { + "SQL": "select /*+ MERGE_JOIN(t1, t2) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", + "Plan": [ + "HashJoin_9 12500.00 root inner join, equal:[eq(test.t1.a, test.t2.a)]", + "├─TableReader_12(Build) 10000.00 root data:TableFullScan_13", + "│ └─TableFullScan_13 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", + "└─TableReader_14(Probe) 10000.00 root data:TableFullScan_15", + " └─TableFullScan_15 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" + ], + "Result": [ + "1 1" + ] } ] } diff --git a/planner/core/task.go b/planner/core/task.go index 029bf76c91e21..2314c217374bb 100644 --- a/planner/core/task.go +++ b/planner/core/task.go @@ -52,8 +52,8 @@ type copTask struct { indexPlanFinished bool // keepOrder indicates if the plan scans data by order. keepOrder bool - // In double read case, it may output one more column for handle(row id). - // We need to prune it, so we add a project do this. + // doubleReadNeedProj means an extra prune is needed because + // in double read case, it may output one more column for handle(row id). doubleReadNeedProj bool extraHandleCol *expression.Column @@ -574,7 +574,6 @@ func (p *PhysicalMergeJoin) attach2Task(tasks ...task) task { lTask := finishCopTask(p.ctx, tasks[0].copy()) rTask := finishCopTask(p.ctx, tasks[1].copy()) p.SetChildren(lTask.plan(), rTask.plan()) - p.schema = BuildPhysicalJoinSchema(p.JoinType, p) return &rootTask{ p: p, cst: lTask.cost() + rTask.cost() + p.GetCost(lTask.count(), rTask.count()), diff --git a/planner/core/testdata/plan_suite_in.json b/planner/core/testdata/plan_suite_in.json index ef04e0cd3fbcc..c8b35259e42a6 100644 --- a/planner/core/testdata/plan_suite_in.json +++ b/planner/core/testdata/plan_suite_in.json @@ -599,7 +599,8 @@ "select 1 from (select /*+ HASH_JOIN(t1) */ t1.a not in (select t2.a from t2) from t1) x;", "select /*+ INL_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", "select /*+ INL_HASH_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", - "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;" + "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", + "select /*+ MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;" ] }, { diff --git a/planner/core/testdata/plan_suite_out.json b/planner/core/testdata/plan_suite_out.json index 92fb917ac8a79..026b00f58e943 100644 --- a/planner/core/testdata/plan_suite_out.json +++ b/planner/core/testdata/plan_suite_out.json @@ -4,15 +4,15 @@ "Cases": [ { "SQL": "select /*+ MERGE_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Best": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)->Projection" + "Best": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)" }, { "SQL": "select /*+ MERGE_JOIN(test.t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(test.t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Best": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)->Projection" + "Best": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)" }, { "SQL": "select /*+ MERGE_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Best": "MergeInnerJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)->Sort}(test.t.a,test.t.a)->Projection" + "Best": "MergeInnerJoin{TableReader(Table(t))->LeftHashJoin{IndexReader(Index(t.f)[[NULL,+inf]])->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)->Sort}(test.t.a,test.t.a)" }, { "SQL": "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", @@ -40,7 +40,7 @@ }, { "SQL": "select /*+ MERGE_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Best": "MergeInnerJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)->Projection" + "Best": "MergeInnerJoin{TableReader(Table(t))->MergeInnerJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)" }, { "SQL": "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", @@ -579,7 +579,7 @@ }, { "SQL": "select * from t where a in (select s.a from t s) order by t.a", - "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t.a,test.t.a)->Projection" + "Best": "MergeInnerJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t.a,test.t.a)" }, { "SQL": "select * from t where exists (select s.a from t s where s.c in (select c from t as k where k.d = s.d) having sum(s.a) = t.a )", @@ -1243,12 +1243,12 @@ "Cases": [ { "SQL": "select /*+ MERGE_JOIN(@sel_1 t1), INL_JOIN(@sel_2 t3) */ t1.a, t1.b from t t1, (select t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)->Projection", + "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)", "Hints": "use_index(@`sel_1` `test`.`t1` ), use_index(@`sel_2` `test`.`t2` ), use_index(@`sel_2` `test`.`t3` `c_d_e`), inl_join(@`sel_2` `test`.`t3`), merge_join(@`sel_1` `test`.`t1`)" }, { "SQL": "select /*+ MERGE_JOIN(@sel_1 t1), INL_JOIN(@qb t3) */ t1.a, t1.b from t t1, (select /*+ QB_NAME(qb) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a", - "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)->Projection", + "Plan": "MergeInnerJoin{TableReader(Table(t))->IndexJoin{TableReader(Table(t))->IndexReader(Index(t.c_d_e)[[NULL,+inf]])}(test.t.a,test.t.c)}(test.t.a,test.t.a)", "Hints": "use_index(@`sel_1` `test`.`t1` ), use_index(@`sel_2` `test`.`t2` ), use_index(@`sel_2` `test`.`t3` `c_d_e`), inl_join(@`sel_2` `test`.`t3`), merge_join(@`sel_1` `test`.`t1`)" }, { @@ -1661,12 +1661,11 @@ { "SQL": "select /*+ TIDB_SMJ(t1, t2) */ t1.a from t t1, t t2 where t1.a = t2.b order by t1.a", "Plan": [ - "Projection_20 12487.50 root test.t.a", - "└─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", - " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", - " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + "MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + "├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", + "│ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + "└─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", + " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1679,12 +1678,11 @@ "Plan": [ "Projection_24 12487.50 root test.t.a", "└─Projection_23 12487.50 root test.t.a, plus(test.t.a, 1)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", - " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", - " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", + " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", + " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1697,12 +1695,11 @@ "Plan": [ "Projection_24 12487.50 root test.t.a", "└─Projection_23 12487.50 root test.t.a, minus(test.t.a, 1)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", - " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", - " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", + " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", + " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1715,12 +1712,11 @@ "Plan": [ "Projection_32 12487.50 root test.t.a", "└─Projection_31 12487.50 root test.t.a, unaryminus(test.t.a)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", - " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", - " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", - " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", + " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", + " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", + " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" ], "Result": [ "2", @@ -1733,12 +1729,11 @@ "Plan": [ "Projection_32 12487.50 root test.t.a", "└─Projection_31 12487.50 root test.t.a, plus(unaryminus(test.t.a), 3)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", - " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", - " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", - " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", + " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", + " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", + " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" ], "Result": [ "2", @@ -1751,12 +1746,11 @@ "Plan": [ "Projection_24 12487.50 root test.t.a", "└─Projection_23 12487.50 root test.t.a, plus(1, test.t.a)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", - " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", - " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", + " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", + " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1769,12 +1763,11 @@ "Plan": [ "Projection_32 12487.50 root test.t.a", "└─Projection_31 12487.50 root test.t.a, minus(1, test.t.a)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", - " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", - " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", - " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", + " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", + " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", + " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" ], "Result": [ "2", @@ -1787,12 +1780,11 @@ "Plan": [ "Projection_32 12487.50 root test.t.a", "└─Projection_31 12487.50 root test.t.a, plus(minus(1, test.t.a), 3)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", - " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", - " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", - " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_26(Build) 9990.00 root index:IndexFullScan_25", + " │ └─IndexFullScan_25 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, desc, stats:pseudo", + " └─IndexReader_24(Probe) 9990.00 root index:IndexFullScan_23", + " └─IndexFullScan_23 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, desc, stats:pseudo" ], "Result": [ "2", @@ -1805,12 +1797,11 @@ "Plan": [ "Projection_24 12487.50 root test.t.a", "└─Projection_23 12487.50 root test.t.a, plus(plus(1, test.t.a), 3)->Column#7", - " └─Projection_20 12487.50 root test.t.a", - " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", - " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", - " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + " └─MergeJoin_21 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_15(Build) 9990.00 root index:IndexFullScan_14", + " │ └─IndexFullScan_14 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + " └─IndexReader_13(Probe) 9990.00 root index:IndexFullScan_12", + " └─IndexFullScan_12 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1824,12 +1815,11 @@ "Projection_19 12487.50 root test.t.a", "└─Sort_7 12487.50 root Column#7:asc", " └─Projection_20 12487.50 root test.t.a, mul(3, test.t.a)->Column#7", - " └─Projection_8 12487.50 root test.t.a", - " └─MergeJoin_9 12487.50 root inner join, left key:test.t.a, right key:test.t.b", - " ├─IndexReader_14(Build) 9990.00 root index:IndexFullScan_13", - " │ └─IndexFullScan_13 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", - " └─IndexReader_12(Probe) 9990.00 root index:IndexFullScan_11", - " └─IndexFullScan_11 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" + " └─MergeJoin_9 12487.50 root inner join, left key:test.t.a, right key:test.t.b", + " ├─IndexReader_14(Build) 9990.00 root index:IndexFullScan_13", + " │ └─IndexFullScan_13 9990.00 cop[tikv] table:t2, index:idx_b(b) keep order:true, stats:pseudo", + " └─IndexReader_12(Probe) 9990.00 root index:IndexFullScan_11", + " └─IndexFullScan_11 9990.00 cop[tikv] table:t1, index:idx_a(a) keep order:true, stats:pseudo" ], "Result": [ "1", @@ -1886,6 +1876,11 @@ "SQL": "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", "Plan": "IndexMergeJoin{IndexLookUp(Index(t1.idx_a)[[NULL,+inf]]->Sel([not(isnull(test.t1.a))]), Table(t1))->Projection->TableReader(Table(t2)->Sel([not(isnull(test.t2.a))]))}(test.t2.a,test.t1.a)", "Hints": "use_index(@`sel_1` `test`.`t1` `idx_a`), use_index(@`sel_1` `test`.`t2` )" + }, + { + "SQL": "select /*+ MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;", + "Plan": "MergeInnerJoin{IndexLookUp(Index(t1.idx_a)[[-inf,+inf]], Table(t1))->Projection->IndexLookUp(Index(t2.idx_a)[[-inf,+inf]], Table(t2))->Projection}(test.t1.a,test.t2.a)", + "Hints": "use_index(@`sel_1` `test`.`t1` `idx_a`), use_index(@`sel_1` `test`.`t2` `idx_a`)" } ] }, diff --git a/planner/implementation/join.go b/planner/implementation/join.go index 3b801ccae3704..35abf19e8086c 100644 --- a/planner/implementation/join.go +++ b/planner/implementation/join.go @@ -64,7 +64,6 @@ func (impl *MergeJoinImpl) CalcCost(outCount float64, children ...memo.Implement func (impl *MergeJoinImpl) AttachChildren(children ...memo.Implementation) memo.Implementation { mergeJoin := impl.plan.(*plannercore.PhysicalMergeJoin) mergeJoin.SetChildren(children[0].GetPlan(), children[1].GetPlan()) - mergeJoin.SetSchema(plannercore.BuildPhysicalJoinSchema(mergeJoin.JoinType, mergeJoin)) return impl }