Skip to content

Commit 5290b86

Browse files
Improve UNION query merging (vitessio#18289)
Signed-off-by: Arthur Schreiber <arthurschreiber@github.com>
1 parent 3aef1b4 commit 5290b86

File tree

6 files changed

+194
-77
lines changed

6 files changed

+194
-77
lines changed

go/vt/sqlparser/normalizer.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type (
4545
bindVars map[string]*querypb.BindVariable
4646
reserved *ReservedVars
4747
vals map[Literal]string
48+
tupleVals map[string]string
4849
err error
4950
inDerived int
5051
inSelect int
@@ -145,6 +146,7 @@ func newNormalizer(
145146
bindVars: bindVars,
146147
reserved: reserved,
147148
vals: make(map[Literal]string),
149+
tupleVals: make(map[string]string),
148150
bindVarNeeds: &BindVarNeeds{},
149151
keyspace: keyspace,
150152
selectLimit: selectLimit,
@@ -470,8 +472,22 @@ func (nz *normalizer) rewriteInComparisons(node *ComparisonExpr) {
470472
Value: bval.Value,
471473
})
472474
}
473-
bvname := nz.reserved.nextUnusedVar()
474-
nz.bindVars[bvname] = bvals
475+
476+
var bvname string
477+
478+
if key, err := bvals.MarshalVT(); err != nil {
479+
bvname = nz.reserved.nextUnusedVar()
480+
nz.bindVars[bvname] = bvals
481+
} else {
482+
// Check if we can find key in tuplevals
483+
if bvname, ok = nz.tupleVals[string(key)]; !ok {
484+
bvname = nz.reserved.nextUnusedVar()
485+
}
486+
487+
nz.bindVars[bvname] = bvals
488+
nz.tupleVals[string(key)] = bvname
489+
}
490+
475491
node.Right = ListArg(bvname)
476492
}
477493

go/vt/sqlparser/normalizer_test.go

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,13 @@ func TestNormalize(t *testing.T) {
317317
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
318318
},
319319
}, {
320-
// EXPLAIN query will be normalized and not parameterized
320+
// repeated IN clause with vals
321+
in: "select * from t where v1 in (1, '2') OR v2 in (1, '2')",
322+
outstmt: "select * from t where v1 in ::bv1 or v2 in ::bv1",
323+
outbv: map[string]*querypb.BindVariable{
324+
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
325+
},
326+
}, { // EXPLAIN query will be normalized and not parameterized
321327
in: "explain select @x from t where v1 in (1, '2')",
322328
outstmt: "explain select :__vtudvx as `@x` from t where v1 in (1, '2')",
323329
outbv: map[string]*querypb.BindVariable{},
@@ -1325,9 +1331,9 @@ JOIN warehouse%d AS w ON c_w_id=w_id
13251331
WHERE w_id = %d
13261332
AND c_d_id = %d
13271333
AND c_id = %d`,
1328-
`SELECT d_next_o_id, d_tax
1329-
FROM district%d
1330-
WHERE d_w_id = %d
1334+
`SELECT d_next_o_id, d_tax
1335+
FROM district%d
1336+
WHERE d_w_id = %d
13311337
AND d_id = %d FOR UPDATE`,
13321338
`UPDATE district%d
13331339
SET d_next_o_id = %d
@@ -1337,130 +1343,130 @@ WHERE d_id = %d AND d_w_id= %d`,
13371343
VALUES (%d,%d,%d,%d,NOW(),%d,%d)`,
13381344
`INSERT INTO new_orders%d (no_o_id, no_d_id, no_w_id)
13391345
VALUES (%d,%d,%d)`,
1340-
`SELECT i_price, i_name, i_data
1346+
`SELECT i_price, i_name, i_data
13411347
FROM item%d
13421348
WHERE i_id = %d`,
1343-
`SELECT s_quantity, s_data, s_dist_%s s_dist
1344-
FROM stock%d
1349+
`SELECT s_quantity, s_data, s_dist_%s s_dist
1350+
FROM stock%d
13451351
WHERE s_i_id = %d AND s_w_id= %d FOR UPDATE`,
13461352
`UPDATE stock%d
13471353
SET s_quantity = %d
1348-
WHERE s_i_id = %d
1354+
WHERE s_i_id = %d
13491355
AND s_w_id= %d`,
13501356
`INSERT INTO order_line%d
13511357
(ol_o_id, ol_d_id, ol_w_id, ol_number, ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_dist_info)
13521358
VALUES (%d,%d,%d,%d,%d,%d,%d,%d,'%s')`,
13531359
`UPDATE warehouse%d
1354-
SET w_ytd = w_ytd + %d
1360+
SET w_ytd = w_ytd + %d
13551361
WHERE w_id = %d`,
13561362
`SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name
13571363
FROM warehouse%d
13581364
WHERE w_id = %d`,
1359-
`UPDATE district%d
1360-
SET d_ytd = d_ytd + %d
1361-
WHERE d_w_id = %d
1365+
`UPDATE district%d
1366+
SET d_ytd = d_ytd + %d
1367+
WHERE d_w_id = %d
13621368
AND d_id= %d`,
1363-
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
1369+
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
13641370
FROM district%d
1365-
WHERE d_w_id = %d
1371+
WHERE d_w_id = %d
13661372
AND d_id = %d`,
13671373
`SELECT count(c_id) namecnt
13681374
FROM customer%d
1369-
WHERE c_w_id = %d
1375+
WHERE c_w_id = %d
13701376
AND c_d_id= %d
13711377
AND c_last='%s'`,
13721378
`SELECT c_first, c_middle, c_last, c_street_1,
13731379
c_street_2, c_city, c_state, c_zip, c_phone,
13741380
c_credit, c_credit_lim, c_discount, c_balance, c_ytd_payment, c_since
13751381
FROM customer%d
1376-
WHERE c_w_id = %d
1382+
WHERE c_w_id = %d
13771383
AND c_d_id= %d
13781384
AND c_id=%d FOR UPDATE`,
13791385
`SELECT c_data
13801386
FROM customer%d
1381-
WHERE c_w_id = %d
1387+
WHERE c_w_id = %d
13821388
AND c_d_id=%d
13831389
AND c_id= %d`,
13841390
`UPDATE customer%d
13851391
SET c_balance=%f, c_ytd_payment=%f, c_data='%s'
1386-
WHERE c_w_id = %d
1392+
WHERE c_w_id = %d
13871393
AND c_d_id=%d
13881394
AND c_id=%d`,
13891395
`UPDATE customer%d
13901396
SET c_balance=%f, c_ytd_payment=%f
1391-
WHERE c_w_id = %d
1397+
WHERE c_w_id = %d
13921398
AND c_d_id=%d
13931399
AND c_id=%d`,
13941400
`INSERT INTO history%d
13951401
(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data)
13961402
VALUES (%d,%d,%d,%d,%d,NOW(),%d,'%s')`,
13971403
`SELECT count(c_id) namecnt
13981404
FROM customer%d
1399-
WHERE c_w_id = %d
1405+
WHERE c_w_id = %d
14001406
AND c_d_id= %d
14011407
AND c_last='%s'`,
14021408
`SELECT c_balance, c_first, c_middle, c_id
14031409
FROM customer%d
1404-
WHERE c_w_id = %d
1410+
WHERE c_w_id = %d
14051411
AND c_d_id= %d
14061412
AND c_last='%s' ORDER BY c_first`,
14071413
`SELECT c_balance, c_first, c_middle, c_last
14081414
FROM customer%d
1409-
WHERE c_w_id = %d
1415+
WHERE c_w_id = %d
14101416
AND c_d_id=%d
14111417
AND c_id=%d`,
14121418
`SELECT o_id, o_carrier_id, o_entry_d
1413-
FROM orders%d
1414-
WHERE o_w_id = %d
1415-
AND o_d_id = %d
1416-
AND o_c_id = %d
1419+
FROM orders%d
1420+
WHERE o_w_id = %d
1421+
AND o_d_id = %d
1422+
AND o_c_id = %d
14171423
ORDER BY o_id DESC`,
14181424
`SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d
14191425
FROM order_line%d WHERE ol_w_id = %d AND ol_d_id = %d AND ol_o_id = %d`,
14201426
`SELECT no_o_id
1421-
FROM new_orders%d
1422-
WHERE no_d_id = %d
1423-
AND no_w_id = %d
1427+
FROM new_orders%d
1428+
WHERE no_d_id = %d
1429+
AND no_w_id = %d
14241430
ORDER BY no_o_id ASC LIMIT 1 FOR UPDATE`,
14251431
`DELETE FROM new_orders%d
1426-
WHERE no_o_id = %d
1427-
AND no_d_id = %d
1432+
WHERE no_o_id = %d
1433+
AND no_d_id = %d
14281434
AND no_w_id = %d`,
14291435
`SELECT o_c_id
1430-
FROM orders%d
1431-
WHERE o_id = %d
1432-
AND o_d_id = %d
1436+
FROM orders%d
1437+
WHERE o_id = %d
1438+
AND o_d_id = %d
14331439
AND o_w_id = %d`,
1434-
`UPDATE orders%d
1440+
`UPDATE orders%d
14351441
SET o_carrier_id = %d
1436-
WHERE o_id = %d
1437-
AND o_d_id = %d
1442+
WHERE o_id = %d
1443+
AND o_d_id = %d
14381444
AND o_w_id = %d`,
1439-
`UPDATE order_line%d
1445+
`UPDATE order_line%d
14401446
SET ol_delivery_d = NOW()
1441-
WHERE ol_o_id = %d
1442-
AND ol_d_id = %d
1447+
WHERE ol_o_id = %d
1448+
AND ol_d_id = %d
14431449
AND ol_w_id = %d`,
14441450
`SELECT SUM(ol_amount) sm
1445-
FROM order_line%d
1446-
WHERE ol_o_id = %d
1447-
AND ol_d_id = %d
1451+
FROM order_line%d
1452+
WHERE ol_o_id = %d
1453+
AND ol_d_id = %d
14481454
AND ol_w_id = %d`,
1449-
`UPDATE customer%d
1455+
`UPDATE customer%d
14501456
SET c_balance = c_balance + %f,
14511457
c_delivery_cnt = c_delivery_cnt + 1
1452-
WHERE c_id = %d
1453-
AND c_d_id = %d
1458+
WHERE c_id = %d
1459+
AND c_d_id = %d
14541460
AND c_w_id = %d`,
1455-
`SELECT d_next_o_id
1461+
`SELECT d_next_o_id
14561462
FROM district%d
14571463
WHERE d_id = %d AND d_w_id= %d`,
14581464
`SELECT COUNT(DISTINCT(s.s_i_id))
14591465
FROM stock%d AS s
1460-
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
1461-
WHERE ol.ol_w_id = %d
1466+
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
1467+
WHERE ol.ol_w_id = %d
14621468
AND ol.ol_d_id = %d
1463-
AND ol.ol_o_id < %d
1469+
AND ol.ol_o_id < %d
14641470
AND ol.ol_o_id >= %d
14651471
AND s.s_w_id= %d
14661472
AND s.s_quantity < %d `,
@@ -1471,7 +1477,7 @@ AND ol_o_id < %d AND ol_o_id >= %d`,
14711477
WHERE s_w_id = %d AND s_i_id = %d
14721478
AND s_quantity < %d`,
14731479
`SELECT min(no_o_id) mo
1474-
FROM new_orders%d
1480+
FROM new_orders%d
14751481
WHERE no_w_id = %d AND no_d_id = %d`,
14761482
`SELECT o_id FROM orders%d o, (SELECT o_c_id,o_w_id,o_d_id,count(distinct o_id) FROM orders%d WHERE o_w_id=%d AND o_d_id=%d AND o_id > 2100 AND o_id < %d GROUP BY o_c_id,o_d_id,o_w_id having count( distinct o_id) > 1 limit 1) t WHERE t.o_w_id=o.o_w_id and t.o_d_id=o.o_d_id and t.o_c_id=o.o_c_id limit 1 `,
14771483
`DELETE FROM order_line%d where ol_w_id=%d AND ol_d_id=%d AND ol_o_id=%d`,

go/vt/vtgate/executor_select_test.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3333,33 +3333,17 @@ func TestSelectWithUnionAll(t *testing.T) {
33333333
bv1, _ := sqltypes.BuildBindVariable([]int64{1, 2})
33343334
bv2, _ := sqltypes.BuildBindVariable([]int64{3})
33353335
sbc1WantQueries := []*querypb.BoundQuery{{
3336-
Sql: "select id from `user` where id in ::__vals",
3337-
BindVariables: map[string]*querypb.BindVariable{
3338-
"__vals": bv1,
3339-
"vtg1": bv,
3340-
"vtg2": bv,
3341-
},
3342-
}, {
3343-
Sql: "select id from `user` where id in ::__vals",
3336+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
33443337
BindVariables: map[string]*querypb.BindVariable{
33453338
"__vals": bv1,
33463339
"vtg1": bv,
3347-
"vtg2": bv,
33483340
},
33493341
}}
33503342
sbc2WantQueries := []*querypb.BoundQuery{{
3351-
Sql: "select id from `user` where id in ::__vals",
3352-
BindVariables: map[string]*querypb.BindVariable{
3353-
"__vals": bv2,
3354-
"vtg1": bv,
3355-
"vtg2": bv,
3356-
},
3357-
}, {
3358-
Sql: "select id from `user` where id in ::__vals",
3343+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
33593344
BindVariables: map[string]*querypb.BindVariable{
33603345
"__vals": bv2,
33613346
"vtg1": bv,
3362-
"vtg2": bv,
33633347
},
33643348
}}
33653349
session := &vtgatepb.Session{

go/vt/vtgate/planbuilder/operators/route_planning.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,26 @@ func gen4ValuesEqual(ctx *plancontext.PlanningContext, a, b []sqlparser.Expr) (b
478478
return false, nil
479479
}
480480
if c != nil {
481-
conditions = append(conditions, *c)
481+
conditions = append(conditions, c...)
482482
}
483483
}
484484
return true, conditions
485485
}
486486

487-
func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) (bool, *engine.Condition) {
487+
func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) (bool, []engine.Condition) {
488488
switch a := a.(type) {
489+
case sqlparser.ValTuple:
490+
if b, ok := b.(sqlparser.ValTuple); ok {
491+
return gen4ValuesEqual(ctx, a, b)
492+
}
493+
494+
return false, nil
495+
496+
case sqlparser.ListArg:
497+
if b, ok := b.(sqlparser.ListArg); ok {
498+
return a == b, nil
499+
}
500+
489501
case *sqlparser.ColName:
490502
if b, ok := b.(*sqlparser.ColName); ok {
491503
if !a.Name.Equal(b.Name) {
@@ -518,7 +530,7 @@ func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) (bool,
518530
}
519531

520532
return aVal.Type == bVal.Type && bytes.Equal(aVal.Value, bVal.Value),
521-
&engine.Condition{A: a.Name, B: b.Name}
533+
[]engine.Condition{{A: a.Name, B: b.Name}}
522534

523535
case *sqlparser.Literal:
524536
b, ok := b.(*sqlparser.Literal)

go/vt/vtgate/planbuilder/operators/union_merging.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ func tryMergeUnionShardedRouting(
146146

147147
scatterA := tblA.RouteOpCode == engine.Scatter
148148
scatterB := tblB.RouteOpCode == engine.Scatter
149-
uniqueA := tblA.RouteOpCode == engine.EqualUnique
150-
uniqueB := tblB.RouteOpCode == engine.EqualUnique
151149

152150
switch {
153151
case scatterA:
@@ -156,7 +154,11 @@ func tryMergeUnionShardedRouting(
156154
case scatterB:
157155
return createMergedUnion(ctx, routeA, routeB, exprsA, exprsB, distinct, tblB, nil)
158156

159-
case uniqueA && uniqueB:
157+
case tblA.RouteOpCode == engine.EqualUnique && tblB.RouteOpCode == engine.EqualUnique:
158+
fallthrough
159+
case tblA.RouteOpCode == engine.Equal && tblB.RouteOpCode == engine.Equal:
160+
fallthrough
161+
case tblA.RouteOpCode == engine.IN && tblB.RouteOpCode == engine.IN:
160162
aVdx := tblA.SelectedVindex()
161163
bVdx := tblB.SelectedVindex()
162164
aExpr := tblA.VindexExpressions()

0 commit comments

Comments
 (0)