Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: outer merge join cannot keep the prop of its inner child (#33359) #33369

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,22 @@ func (p *LogicalJoin) getEnforcedMergeJoin(prop *property.PhysicalProperty, sche
if !all {
return nil
}
<<<<<<< HEAD
for _, item := range prop.Items {
isExist := false
=======
for _, item := range prop.SortItems {
isExist, hasLeftColInProp, hasRightColInProp := false, false, false
>>>>>>> 1287eab59... planner: outer merge join cannot keep the prop of its inner child (#33359)
for joinKeyPos := 0; joinKeyPos < len(leftJoinKeys); joinKeyPos++ {
var key *expression.Column
if item.Col.Equal(p.ctx, leftJoinKeys[joinKeyPos]) {
key = leftJoinKeys[joinKeyPos]
hasLeftColInProp = true
}
if item.Col.Equal(p.ctx, rightJoinKeys[joinKeyPos]) {
key = rightJoinKeys[joinKeyPos]
hasRightColInProp = true
}
if key == nil {
continue
Expand All @@ -275,6 +282,13 @@ func (p *LogicalJoin) getEnforcedMergeJoin(prop *property.PhysicalProperty, sche
if !isExist {
return nil
}
// If the output wants the order of the inner side. We should reject it since we might add null-extend rows of that side.
if p.JoinType == LeftOuterJoin && hasRightColInProp {
return nil
}
if p.JoinType == RightOuterJoin && hasLeftColInProp {
return nil
}
}
// Generate the enforced sort merge join
leftKeys := getNewJoinKeysByOffsets(leftJoinKeys, offsets)
Expand Down
21 changes: 21 additions & 0 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2161,3 +2161,24 @@ func (s *testIntegrationSuite) TestIssues29711(c *C) {
))

}

func TestIssue33042(t *testing.T) {
store, _, clean := testkit.CreateMockStoreAndDomain(t)
defer clean()
tk := testkit.NewTestKit(t, store)

tk.MustExec("use test")
tk.MustExec("create table t1(id int primary key, col1 int)")
tk.MustExec("create table t2(id int primary key, col1 int)")
tk.MustQuery("explain format='brief' SELECT /*+ merge_join(t1, t2)*/ * FROM (t1 LEFT JOIN t2 ON t1.col1=t2.id) order by t2.id;").Check(
testkit.Rows(
"Sort 12500.00 root test.t2.id",
"└─MergeJoin 12500.00 root left outer join, left key:test.t1.col1, right key:test.t2.id",
" ├─TableReader(Build) 10000.00 root data:TableFullScan",
" │ └─TableFullScan 10000.00 cop[tikv] table:t2 keep order:true, stats:pseudo",
" └─Sort(Probe) 10000.00 root test.t1.col1",
" └─TableReader 10000.00 root data:TableFullScan",
" └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
),
)
}
203 changes: 203 additions & 0 deletions planner/core/testdata/integration_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,210 @@
"└─TableReader_14 10000.00 root data:TableFullScan_13",
" └─TableFullScan_13 10000.00 cop[tiflash] table:t, partition:p2 keep order:false, stats:pseudo"
],
<<<<<<< HEAD
"Warn": null
=======
"Res": [
"1 111 1.1000000000 11 1 111 1.1000000000 11",
"2 222 2.2000000000 12 2 222 2.2000000000 12",
"3 333 3.3000000000 13 3 333 3.3000000000 13"
]
},
{
"SQL": "select /*+ inl_join(t1, t2) */ * from t t1 join t t2 on t1.c = t2.c",
"Plan": [
"IndexJoin 3.00 root inner join, inner:IndexLookUp, outer key:test.t.c, inner key:test.t.c, equal cond:eq(test.t.c, test.t.c)",
"├─TableReader(Build) 3.00 root data:Selection",
"│ └─Selection 3.00 cop[tikv] not(isnull(test.t.c))",
"│ └─TableFullScan 3.00 cop[tikv] table:t1 keep order:false",
"└─IndexLookUp(Probe) 1.00 root ",
" ├─Selection(Build) 1.00 cop[tikv] not(isnull(test.t.c))",
" │ └─IndexRangeScan 1.00 cop[tikv] table:t2, index:c(c) range: decided by [eq(test.t.c, test.t.c)], keep order:false",
" └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false"
],
"Res": [
"1 111 1.1000000000 11 1 111 1.1000000000 11",
"2 222 2.2000000000 12 2 222 2.2000000000 12",
"3 333 3.3000000000 13 3 333 3.3000000000 13"
]
},
{
"SQL": "select /*+ inl_merge_join(t1,t2) */ t2.a, t2.c, t2.d from t t1 left join t t2 on t1.a = t2.c;",
"Plan": [
"IndexMergeJoin 3.00 root left outer join, inner:Projection, outer key:Column#9, inner key:test.t.c",
"├─Projection(Build) 3.00 root cast(test.t.a, decimal(20,0) BINARY)->Column#9",
"│ └─TableReader 3.00 root data:TableFullScan",
"│ └─TableFullScan 3.00 cop[tikv] table:t1 keep order:false",
"└─Projection(Probe) 1.00 root test.t.a, test.t.c, test.t.d",
" └─IndexLookUp 1.00 root ",
" ├─IndexRangeScan(Build) 1.00 cop[tikv] table:t2, index:c(c) range: decided by [eq(test.t.c, Column#9)], keep order:true",
" └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false"
],
"Res": [
"<nil> <nil> <nil>",
"<nil> <nil> <nil>",
"<nil> <nil> <nil>"
]
}
]
},
{
"Name": "TestPartitionExplain",
"Cases": [
{
"SQL": "select * from pt where c > 10",
"Plan": [
"TableReader_7 3333.33 root partition:dual data:Selection_6",
"└─Selection_6 3333.33 cop[tikv] gt(test.pt.c, 10)",
" └─TableFullScan_5 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select * from pt where c > 8",
"Plan": [
"TableReader_7 3333.33 root partition:p2 data:Selection_6",
"└─Selection_6 3333.33 cop[tikv] gt(test.pt.c, 8)",
" └─TableFullScan_5 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select * from pt where c < 2 or c >= 9",
"Plan": [
"TableReader_7 6656.67 root partition:p0,p2 data:Selection_6",
"└─Selection_6 6656.67 cop[tikv] or(lt(test.pt.c, 2), ge(test.pt.c, 9))",
" └─TableFullScan_5 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select c from pt",
"Plan": [
"IndexReader_7 10000.00 root partition:all index:IndexFullScan_6",
"└─IndexFullScan_6 10000.00 cop[tikv] table:pt, index:i_c(c) keep order:false, stats:pseudo"
]
},
{
"SQL": "select c from pt where c > 10",
"Plan": [
"IndexReader_6 3333.33 root partition:dual index:IndexRangeScan_5",
"└─IndexRangeScan_5 3333.33 cop[tikv] table:pt, index:i_c(c) range:(10,+inf], keep order:false, stats:pseudo"
]
},
{
"SQL": "select c from pt where c > 8",
"Plan": [
"IndexReader_6 3333.33 root partition:p2 index:IndexRangeScan_5",
"└─IndexRangeScan_5 3333.33 cop[tikv] table:pt, index:i_c(c) range:(8,+inf], keep order:false, stats:pseudo"
]
},
{
"SQL": "select c from pt where c < 2 or c >= 9",
"Plan": [
"IndexReader_6 6656.67 root partition:p0,p2 index:IndexRangeScan_5",
"└─IndexRangeScan_5 6656.67 cop[tikv] table:pt, index:i_c(c) range:[-inf,2), [9,+inf], keep order:false, stats:pseudo"
]
},
{
"SQL": "select /*+ use_index(pt, i_id) */ * from pt",
"Plan": [
"IndexLookUp_6 10000.00 root partition:all ",
"├─IndexFullScan_4(Build) 10000.00 cop[tikv] table:pt, index:i_id(id) keep order:false, stats:pseudo",
"└─TableRowIDScan_5(Probe) 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select /*+ use_index(pt, i_id) */ * from pt where id < 4 and c > 10",
"Plan": [
"IndexLookUp_8 1107.78 root partition:dual ",
"├─IndexRangeScan_5(Build) 3323.33 cop[tikv] table:pt, index:i_id(id) range:[-inf,4), keep order:false, stats:pseudo",
"└─Selection_7(Probe) 1107.78 cop[tikv] gt(test.pt.c, 10)",
" └─TableRowIDScan_6 3323.33 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select /*+ use_index(pt, i_id) */ * from pt where id < 10 and c > 8",
"Plan": [
"IndexLookUp_8 1107.78 root partition:p2 ",
"├─IndexRangeScan_5(Build) 3323.33 cop[tikv] table:pt, index:i_id(id) range:[-inf,10), keep order:false, stats:pseudo",
"└─Selection_7(Probe) 1107.78 cop[tikv] gt(test.pt.c, 8)",
" └─TableRowIDScan_6 3323.33 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select /*+ use_index(pt, i_id) */ * from pt where id < 10 and c < 2 or c >= 9",
"Plan": [
"IndexLookUp_8 5325.33 root partition:p0,p2 ",
"├─IndexFullScan_5(Build) 10000.00 cop[tikv] table:pt, index:i_id(id) keep order:false, stats:pseudo",
"└─Selection_7(Probe) 5325.33 cop[tikv] or(and(lt(test.pt.id, 10), lt(test.pt.c, 2)), ge(test.pt.c, 9))",
" └─TableRowIDScan_6 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select * from pt partition (p0) where c > 8",
"Plan": [
"TableReader_7 3333.33 root partition:dual data:Selection_6",
"└─Selection_6 3333.33 cop[tikv] gt(test.pt.c, 8)",
" └─TableFullScan_5 10000.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select c from pt partition (p0, p2) where c > 8",
"Plan": [
"IndexReader_6 3333.33 root partition:p2 index:IndexRangeScan_5",
"└─IndexRangeScan_5 3333.33 cop[tikv] table:pt, index:i_c(c) range:(8,+inf], keep order:false, stats:pseudo"
]
},
{
"SQL": "select /*+ use_index(pt, i_id) */ * from pt partition (p1, p2) where c < 3 and id = 5",
"Plan": [
"IndexLookUp_8 3.32 root partition:dual ",
"├─IndexRangeScan_5(Build) 10.00 cop[tikv] table:pt, index:i_id(id) range:[5,5], keep order:false, stats:pseudo",
"└─Selection_7(Probe) 3.32 cop[tikv] lt(test.pt.c, 3)",
" └─TableRowIDScan_6 10.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select * from pt where id = 4 or c < 7",
"Plan": [
"IndexMerge_11 3330.01 root partition:all ",
"├─IndexRangeScan_8(Build) 10.00 cop[tikv] table:pt, index:i_id(id) range:[4,4], keep order:false, stats:pseudo",
"├─IndexRangeScan_9(Build) 3323.33 cop[tikv] table:pt, index:i_c(c) range:[-inf,7), keep order:false, stats:pseudo",
"└─TableRowIDScan_10(Probe) 3330.01 cop[tikv] table:pt keep order:false, stats:pseudo"
]
},
{
"SQL": "select * from pt where id > 4 or c = 7",
"Plan": [
"IndexMerge_11 3340.00 root partition:all ",
"├─IndexRangeScan_8(Build) 3333.33 cop[tikv] table:pt, index:i_id(id) range:(4,+inf], keep order:false, stats:pseudo",
"├─IndexRangeScan_9(Build) 10.00 cop[tikv] table:pt, index:i_c(c) range:[7,7], keep order:false, stats:pseudo",
"└─TableRowIDScan_10(Probe) 3340.00 cop[tikv] table:pt keep order:false, stats:pseudo"
]
}
]
},
{
"Name": "TestInvalidHint",
"Cases": [
{
"SQL": "explain format = 'brief' select /*+ use_index_merge(tt) */ * from tt where a=10 or a=20;",
"Plan": [
"IndexReader 20.00 root index:IndexRangeScan",
"└─IndexRangeScan 20.00 cop[tikv] table:tt, index:a(a) range:[10,10], [20,20], keep order:false, stats:pseudo"
],
"Warnings": [
"Warning 1105 IndexMerge is inapplicable"
]
},
{
"SQL": "explain format = 'brief' select /*+ use_index_merge(tt) */ * from tt where a=15 or (a < 10 or a > 20);",
"Plan": [
"IndexReader 6666.67 root index:IndexRangeScan",
"└─IndexRangeScan 6666.67 cop[tikv] table:tt, index:a(a) range:[-inf,10), [15,15], (20,+inf], keep order:false, stats:pseudo"
],
"Warnings": [
"Warning 1105 IndexMerge is inapplicable"
]
>>>>>>> 1287eab59... planner: outer merge join cannot keep the prop of its inner child (#33359)
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion planner/core/testdata/plan_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@
},
{
"SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t2.a = t3.a",
"Best": "MergeLeftOuterJoin{MergeLeftOuterJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t.a,test.t.a)->TableReader(Table(t))}(test.t.a,test.t.a)"
"Best": "MergeLeftOuterJoin{MergeLeftOuterJoin{TableReader(Table(t))->TableReader(Table(t))}(test.t.a,test.t.a)->Sort->TableReader(Table(t))}(test.t.a,test.t.a)"
},
{
"SQL": "select /*+ TIDB_SMJ(t1,t2,t3)*/ * from t t1 left outer join t t2 on t1.a = t2.a left outer join t t3 on t1.a = t3.a",
Expand Down