@@ -47,7 +47,7 @@ var JoinPlanningTests = []struct {
47
47
{
48
48
name : "merge join unary index" ,
49
49
setup : []string {
50
- "CREATE table xy (x int primary key, y int, index y_idx(y));" ,
50
+ "CREATE table xy (x int primary key, y int, unique index y_idx(y));" ,
51
51
"create table rs (r int primary key, s int, index s_idx(s));" ,
52
52
"CREATE table uv (u int primary key, v int);" ,
53
53
"CREATE table ab (a int primary key, b int);" ,
@@ -59,54 +59,54 @@ var JoinPlanningTests = []struct {
59
59
},
60
60
tests : []JoinPlanTest {
61
61
{
62
- q : "select u,a,y from uv join (select /*+ JOIN_ORDER(ab, xy) */ * from ab join xy on y = a) r on u = r.a order by 1" ,
62
+ q : "select u,a,y from uv join (select /*+ JOIN_ORDER(ab, xy) MERGE_JOIN(ab, xy) */ * from ab join xy on y = a) r on u = r.a order by 1" ,
63
63
types : []plan.JoinType {plan .JoinTypeLookup , plan .JoinTypeMerge },
64
64
exp : []sql.Row {{0 , 0 , 0 }, {1 , 1 , 1 }, {2 , 2 , 2 }, {3 , 3 , 3 }},
65
65
},
66
66
{
67
- q : "select /*+ JOIN_ORDER(ab, xy) */ * from ab join xy on y = a order by 1, 3" ,
67
+ q : "select /*+ JOIN_ORDER(ab, xy) MERGE_JOIN(ab, xy) */ * from ab join xy on y = a order by 1, 3" ,
68
68
types : []plan.JoinType {plan .JoinTypeMerge },
69
69
exp : []sql.Row {{0 , 2 , 1 , 0 }, {1 , 2 , 2 , 1 }, {2 , 2 , 0 , 2 }, {3 , 1 , 3 , 3 }},
70
70
},
71
71
{
72
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs left join xy on y = s order by 1, 3" ,
72
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs left join xy on y = s order by 1, 3" ,
73
73
types : []plan.JoinType {plan .JoinTypeLeftOuterMerge },
74
74
exp : []sql.Row {{0 , 0 , 1 , 0 }, {1 , 0 , 1 , 0 }, {2 , 0 , 1 , 0 }, {4 , 4 , nil , nil }, {5 , 4 , nil , nil }},
75
75
},
76
76
{
77
77
// extra join condition does not filter left-only rows
78
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs left join xy on y = s and y+s = 0 order by 1, 3" ,
78
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs left join xy on y = s and y+s = 0 order by 1, 3" ,
79
79
types : []plan.JoinType {plan .JoinTypeLeftOuterMerge },
80
80
exp : []sql.Row {{0 , 0 , 1 , 0 }, {1 , 0 , 1 , 0 }, {2 , 0 , 1 , 0 }, {4 , 4 , nil , nil }, {5 , 4 , nil , nil }},
81
81
},
82
82
{
83
83
// extra join condition does not filter left-only rows
84
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs left join xy on y+2 = s and s-y = 2 order by 1, 3" ,
84
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs left join xy on y+2 = s and s-y = 2 order by 1, 3" ,
85
85
types : []plan.JoinType {plan .JoinTypeLeftOuterMerge },
86
86
exp : []sql.Row {{0 , 0 , nil , nil }, {1 , 0 , nil , nil }, {2 , 0 , nil , nil }, {4 , 4 , 0 , 2 }, {5 , 4 , 0 , 2 }},
87
87
},
88
88
{
89
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = r order by 1, 3" ,
89
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = r order by 1, 3" ,
90
90
types : []plan.JoinType {plan .JoinTypeMerge },
91
91
exp : []sql.Row {{0 , 0 , 1 , 0 }, {1 , 0 , 2 , 1 }, {2 , 0 , 0 , 2 }},
92
92
},
93
93
{
94
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on r = y order by 1, 3" ,
94
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on r = y order by 1, 3" ,
95
95
types : []plan.JoinType {plan .JoinTypeMerge },
96
96
exp : []sql.Row {{0 , 0 , 1 , 0 }, {1 , 0 , 2 , 1 }, {2 , 0 , 0 , 2 }},
97
97
},
98
98
{
99
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s order by 1, 3" ,
99
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s order by 1, 3" ,
100
100
types : []plan.JoinType {plan .JoinTypeMerge },
101
101
exp : []sql.Row {{0 , 0 , 1 , 0 }, {1 , 0 , 1 , 0 }, {2 , 0 , 1 , 0 }},
102
102
},
103
103
{
104
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s and y = r order by 1, 3" ,
104
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s and y = r order by 1, 3" ,
105
105
types : []plan.JoinType {plan .JoinTypeMerge },
106
106
exp : []sql.Row {{0 , 0 , 1 , 0 }},
107
107
},
108
108
{
109
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y+2 = s order by 1, 3" ,
109
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y+2 = s order by 1, 3" ,
110
110
types : []plan.JoinType {plan .JoinTypeMerge },
111
111
exp : []sql.Row {{4 , 4 , 0 , 2 }, {5 , 4 , 0 , 2 }},
112
112
},
@@ -122,12 +122,12 @@ var JoinPlanningTests = []struct {
122
122
// exp: []sql.Row{{0,0,1,0},{0, 0, 1, 0},{2,0,1,0},{4,4,1,0}},
123
123
//},
124
124
{
125
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on 2 = s+y order by 1, 3" ,
125
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on 2 = s+y order by 1, 3" ,
126
126
types : []plan.JoinType {plan .JoinTypeInner },
127
127
exp : []sql.Row {{0 , 0 , 0 , 2 }, {1 , 0 , 0 , 2 }, {2 , 0 , 0 , 2 }},
128
128
},
129
129
{
130
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y > s+2 order by 1, 3" ,
130
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y > s+2 order by 1, 3" ,
131
131
types : []plan.JoinType {plan .JoinTypeInner },
132
132
exp : []sql.Row {{0 , 0 , 3 , 3 }, {1 , 0 , 3 , 3 }, {2 , 0 , 3 , 3 }},
133
133
},
@@ -144,7 +144,7 @@ var JoinPlanningTests = []struct {
144
144
},
145
145
tests : []JoinPlanTest {
146
146
{
147
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
147
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
148
148
types : []plan.JoinType {plan .JoinTypeMerge },
149
149
exp : []sql.Row {{0 , 0 , 1 , 0 }, {0 , 0 , 4 , 0 }, {3 , 0 , 1 , 0 }, {3 , 0 , 4 , 0 }, {4 , 8 , 0 , 8 }, {5 , 4 , 5 , 4 }},
150
150
},
@@ -161,12 +161,37 @@ var JoinPlanningTests = []struct {
161
161
},
162
162
tests : []JoinPlanTest {
163
163
{
164
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
164
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
165
165
types : []plan.JoinType {plan .JoinTypeMerge },
166
166
exp : []sql.Row {},
167
167
},
168
168
},
169
169
},
170
+ {
171
+ name : "merge join large and small table" ,
172
+ setup : []string {
173
+ "CREATE table xy (x int primary key, y int, index y_idx(y));" ,
174
+ "create table rs (r int primary key, s int, index s_idx(s));" ,
175
+ "insert into xy values (1,0), (2,1), (0,8), (3,7), (5,4), (4,0);" ,
176
+ "insert into rs values (0,0),(2,3),(3,0), (4,8), (5,4);" ,
177
+ "update information_schema.statistics set cardinality = 10 where table_name = 'xy';" ,
178
+ "update information_schema.statistics set cardinality = 1000000000 where table_name = 'rs';" ,
179
+ },
180
+ tests : []JoinPlanTest {
181
+ {
182
+ // When primary table is much larger, doing many lookups is expensive: prefer merge
183
+ q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on x = r order by 1,3" ,
184
+ types : []plan.JoinType {plan .JoinTypeMerge },
185
+ exp : []sql.Row {{0 , 0 , 0 , 8 }, {2 , 3 , 2 , 1 }, {3 , 0 , 3 , 7 }, {4 , 8 , 4 , 0 }, {5 , 4 , 5 , 4 }},
186
+ },
187
+ {
188
+ // When secondary table is much larger, avoid reading the entire table: prefer lookup
189
+ q : "select /*+ JOIN_ORDER(xy, rs) */ * from xy join rs on x = r order by 1,3" ,
190
+ types : []plan.JoinType {plan .JoinTypeLookup },
191
+ exp : []sql.Row {{0 , 8 , 0 , 0 }, {2 , 1 , 2 , 3 }, {3 , 7 , 3 , 0 }, {4 , 0 , 4 , 8 }, {5 , 4 , 5 , 4 }},
192
+ },
193
+ },
194
+ },
170
195
{
171
196
name : "merge join multi arity" ,
172
197
setup : []string {
@@ -178,7 +203,7 @@ var JoinPlanningTests = []struct {
178
203
},
179
204
tests : []JoinPlanTest {
180
205
{
181
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
206
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
182
207
types : []plan.JoinType {plan .JoinTypeMerge },
183
208
exp : []sql.Row {{0 , 0 , 1 , 0 }, {0 , 0 , 4 , 0 }, {3 , 0 , 1 , 0 }, {3 , 0 , 4 , 0 }, {4 , 8 , 0 , 8 }, {5 , 4 , 5 , 4 }},
184
209
},
@@ -193,7 +218,7 @@ var JoinPlanningTests = []struct {
193
218
q : `SELECT /*+ MERGE_JOIN(l,r) */ l.pk1, l.pk2, l.c1, r.pk1, r.pk2, r.c1 FROM two_pk l JOIN two_pk r ON l.pk1=r.pk1 AND l.pk2=r.pk2` ,
194
219
types : []plan.JoinType {plan .JoinTypeMerge },
195
220
mergeCompares : []string {"((r.pk1, r.pk2) = (l.pk1, l.pk2))" },
196
- exp : []sql.Row {sql. Row {0 , 0 , 0 , 0 , 0 , 0 }, sql. Row {0 , 1 , 10 , 0 , 1 , 10 }, sql. Row {1 , 0 , 20 , 1 , 0 , 20 }, sql. Row {1 , 1 , 30 , 1 , 1 , 30 }},
221
+ exp : []sql.Row {{0 , 0 , 0 , 0 , 0 , 0 }, {0 , 1 , 10 , 0 , 1 , 10 }, {1 , 0 , 20 , 1 , 0 , 20 }, {1 , 1 , 30 , 1 , 1 , 30 }},
197
222
},
198
223
},
199
224
},
@@ -208,7 +233,7 @@ var JoinPlanningTests = []struct {
208
233
},
209
234
tests : []JoinPlanTest {
210
235
{
211
- q : "select /*+ JOIN_ORDER(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
236
+ q : "select /*+ JOIN_ORDER(rs, xy) MERGE_JOIN(rs, xy) */ * from rs join xy on y = s order by 1,3" ,
212
237
types : []plan.JoinType {plan .JoinTypeMerge },
213
238
exp : []sql.Row {{0 , 0 , 1 , 0 }, {0 , 0 , 4 , 0 }, {3 , 0 , 1 , 0 }, {3 , 0 , 4 , 0 }, {4 , 8 , 0 , 8 }, {5 , 4 , 5 , 4 }},
214
239
},
@@ -266,7 +291,7 @@ var JoinPlanningTests = []struct {
266
291
},
267
292
{
268
293
q : "select * from xy where x not in (select u from uv where u not in (select a from ab where a not in (select r from rs where r = 1))) order by 1;" ,
269
- types : []plan.JoinType {plan .JoinTypeLeftOuterHashExcludeNulls , plan .JoinTypeLeftOuterHashExcludeNulls , plan .JoinTypeAntiLookup },
294
+ types : []plan.JoinType {plan .JoinTypeLeftOuterHashExcludeNulls , plan .JoinTypeLeftOuterHashExcludeNulls , plan .JoinTypeLeftOuterMerge },
270
295
exp : []sql.Row {{0 , 2 }, {2 , 1 }, {3 , 3 }},
271
296
},
272
297
{
@@ -357,12 +382,12 @@ order by 1;`,
357
382
},
358
383
{
359
384
q : "select * from xy where x in (select u from uv join ab on u = a and a = 2) order by 1;" ,
360
- types : []plan.JoinType {plan .JoinTypeHash , plan .JoinTypeLookup },
385
+ types : []plan.JoinType {plan .JoinTypeHash , plan .JoinTypeMerge },
361
386
exp : []sql.Row {{2 , 1 }},
362
387
},
363
388
{
364
389
q : "select * from xy where x = (select u from uv join ab on u = a and a = 2) order by 1;" ,
365
- types : []plan.JoinType {plan .JoinTypeLookup , plan .JoinTypeLookup },
390
+ types : []plan.JoinType {plan .JoinTypeLookup , plan .JoinTypeMerge },
366
391
exp : []sql.Row {{2 , 1 }},
367
392
},
368
393
{
@@ -497,7 +522,7 @@ WHERE EXISTS (
497
522
select x from xy where
498
523
not exists (select a from ab where a = x and a = 1) and
499
524
not exists (select a from ab where a = x and a = 2)` ,
500
- types : []plan.JoinType {plan .JoinTypeAntiLookup , plan .JoinTypeAntiLookup },
525
+ types : []plan.JoinType {plan .JoinTypeAntiLookup , plan .JoinTypeLeftOuterMerge },
501
526
exp : []sql.Row {{0 }, {3 }},
502
527
},
503
528
{
@@ -671,7 +696,7 @@ where u in (select * from rec);`,
671
696
tests : []JoinPlanTest {
672
697
{
673
698
q : "select * from xy where x in (select u from uv join ab on u = a and a = 2) order by 1;" ,
674
- types : []plan.JoinType {plan .JoinTypeHash , plan .JoinTypeLookup },
699
+ types : []plan.JoinType {plan .JoinTypeHash , plan .JoinTypeMerge },
675
700
exp : []sql.Row {{2 , 1 }},
676
701
},
677
702
{
@@ -767,7 +792,7 @@ where u in (select * from rec);`,
767
792
},
768
793
{
769
794
q : "select /*+ MERGE_JOIN(xy,scalarSubq0) */ * from xy where x not in (select u from uv WHERE u = 2) order by x" ,
770
- types : []plan.JoinType {plan .JoinTypeAntiLookup },
795
+ types : []plan.JoinType {plan .JoinTypeLeftOuterMerge },
771
796
exp : []sql.Row {
772
797
{0 , 2 },
773
798
{1 , 0 },
0 commit comments