Skip to content

Commit b114204

Browse files
Improve UNION query merging (vitessio#18289)
Signed-off-by: Arthur Schreiber <[email protected]>
1 parent 498a466 commit b114204

File tree

6 files changed

+193
-76
lines changed

6 files changed

+193
-76
lines changed

go/vt/sqlparser/normalizer.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,17 @@ type normalizer struct {
4747
bindVars map[string]*querypb.BindVariable
4848
reserved *ReservedVars
4949
vals map[Literal]string
50+
tupleVals map[string]string
5051
err error
5152
inDerived bool
5253
}
5354

5455
func newNormalizer(reserved *ReservedVars, bindVars map[string]*querypb.BindVariable) *normalizer {
5556
return &normalizer{
56-
bindVars: bindVars,
57-
reserved: reserved,
58-
vals: make(map[Literal]string),
57+
bindVars: bindVars,
58+
reserved: reserved,
59+
vals: make(map[Literal]string),
60+
tupleVals: make(map[string]string),
5961
}
6062
}
6163

@@ -311,8 +313,22 @@ func (nz *normalizer) rewriteInComparisons(node *ComparisonExpr) {
311313
Value: bval.Value,
312314
})
313315
}
314-
bvname := nz.reserved.nextUnusedVar()
315-
nz.bindVars[bvname] = bvals
316+
317+
var bvname string
318+
319+
if key, err := bvals.MarshalVT(); err != nil {
320+
bvname = nz.reserved.nextUnusedVar()
321+
nz.bindVars[bvname] = bvals
322+
} else {
323+
// Check if we can find key in tuplevals
324+
if bvname, ok = nz.tupleVals[string(key)]; !ok {
325+
bvname = nz.reserved.nextUnusedVar()
326+
}
327+
328+
nz.bindVars[bvname] = bvals
329+
nz.tupleVals[string(key)] = bvname
330+
}
331+
316332
// Modify RHS to be a list bindvar.
317333
node.Right = ListArg(bvname)
318334
}

go/vt/sqlparser/normalizer_test.go

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ func TestNormalize(t *testing.T) {
301301
outbv: map[string]*querypb.BindVariable{
302302
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
303303
},
304+
}, {
305+
// repeated IN clause with vals
306+
in: "select * from t where v1 in (1, '2') OR v2 in (1, '2')",
307+
outstmt: "select * from t where v1 in ::bv1 or v2 in ::bv1",
308+
outbv: map[string]*querypb.BindVariable{
309+
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
310+
},
304311
}, {
305312
// NOT IN clause
306313
in: "select * from t where v1 not in (1, '2')",
@@ -715,9 +722,9 @@ JOIN warehouse%d AS w ON c_w_id=w_id
715722
WHERE w_id = %d
716723
AND c_d_id = %d
717724
AND c_id = %d`,
718-
`SELECT d_next_o_id, d_tax
719-
FROM district%d
720-
WHERE d_w_id = %d
725+
`SELECT d_next_o_id, d_tax
726+
FROM district%d
727+
WHERE d_w_id = %d
721728
AND d_id = %d FOR UPDATE`,
722729
`UPDATE district%d
723730
SET d_next_o_id = %d
@@ -727,130 +734,130 @@ WHERE d_id = %d AND d_w_id= %d`,
727734
VALUES (%d,%d,%d,%d,NOW(),%d,%d)`,
728735
`INSERT INTO new_orders%d (no_o_id, no_d_id, no_w_id)
729736
VALUES (%d,%d,%d)`,
730-
`SELECT i_price, i_name, i_data
737+
`SELECT i_price, i_name, i_data
731738
FROM item%d
732739
WHERE i_id = %d`,
733-
`SELECT s_quantity, s_data, s_dist_%s s_dist
734-
FROM stock%d
740+
`SELECT s_quantity, s_data, s_dist_%s s_dist
741+
FROM stock%d
735742
WHERE s_i_id = %d AND s_w_id= %d FOR UPDATE`,
736743
`UPDATE stock%d
737744
SET s_quantity = %d
738-
WHERE s_i_id = %d
745+
WHERE s_i_id = %d
739746
AND s_w_id= %d`,
740747
`INSERT INTO order_line%d
741748
(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)
742749
VALUES (%d,%d,%d,%d,%d,%d,%d,%d,'%s')`,
743750
`UPDATE warehouse%d
744-
SET w_ytd = w_ytd + %d
751+
SET w_ytd = w_ytd + %d
745752
WHERE w_id = %d`,
746753
`SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name
747754
FROM warehouse%d
748755
WHERE w_id = %d`,
749-
`UPDATE district%d
750-
SET d_ytd = d_ytd + %d
751-
WHERE d_w_id = %d
756+
`UPDATE district%d
757+
SET d_ytd = d_ytd + %d
758+
WHERE d_w_id = %d
752759
AND d_id= %d`,
753-
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
760+
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
754761
FROM district%d
755-
WHERE d_w_id = %d
762+
WHERE d_w_id = %d
756763
AND d_id = %d`,
757764
`SELECT count(c_id) namecnt
758765
FROM customer%d
759-
WHERE c_w_id = %d
766+
WHERE c_w_id = %d
760767
AND c_d_id= %d
761768
AND c_last='%s'`,
762769
`SELECT c_first, c_middle, c_last, c_street_1,
763770
c_street_2, c_city, c_state, c_zip, c_phone,
764771
c_credit, c_credit_lim, c_discount, c_balance, c_ytd_payment, c_since
765772
FROM customer%d
766-
WHERE c_w_id = %d
773+
WHERE c_w_id = %d
767774
AND c_d_id= %d
768775
AND c_id=%d FOR UPDATE`,
769776
`SELECT c_data
770777
FROM customer%d
771-
WHERE c_w_id = %d
778+
WHERE c_w_id = %d
772779
AND c_d_id=%d
773780
AND c_id= %d`,
774781
`UPDATE customer%d
775782
SET c_balance=%f, c_ytd_payment=%f, c_data='%s'
776-
WHERE c_w_id = %d
783+
WHERE c_w_id = %d
777784
AND c_d_id=%d
778785
AND c_id=%d`,
779786
`UPDATE customer%d
780787
SET c_balance=%f, c_ytd_payment=%f
781-
WHERE c_w_id = %d
788+
WHERE c_w_id = %d
782789
AND c_d_id=%d
783790
AND c_id=%d`,
784791
`INSERT INTO history%d
785792
(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data)
786793
VALUES (%d,%d,%d,%d,%d,NOW(),%d,'%s')`,
787794
`SELECT count(c_id) namecnt
788795
FROM customer%d
789-
WHERE c_w_id = %d
796+
WHERE c_w_id = %d
790797
AND c_d_id= %d
791798
AND c_last='%s'`,
792799
`SELECT c_balance, c_first, c_middle, c_id
793800
FROM customer%d
794-
WHERE c_w_id = %d
801+
WHERE c_w_id = %d
795802
AND c_d_id= %d
796803
AND c_last='%s' ORDER BY c_first`,
797804
`SELECT c_balance, c_first, c_middle, c_last
798805
FROM customer%d
799-
WHERE c_w_id = %d
806+
WHERE c_w_id = %d
800807
AND c_d_id=%d
801808
AND c_id=%d`,
802809
`SELECT o_id, o_carrier_id, o_entry_d
803-
FROM orders%d
804-
WHERE o_w_id = %d
805-
AND o_d_id = %d
806-
AND o_c_id = %d
810+
FROM orders%d
811+
WHERE o_w_id = %d
812+
AND o_d_id = %d
813+
AND o_c_id = %d
807814
ORDER BY o_id DESC`,
808815
`SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d
809816
FROM order_line%d WHERE ol_w_id = %d AND ol_d_id = %d AND ol_o_id = %d`,
810817
`SELECT no_o_id
811-
FROM new_orders%d
812-
WHERE no_d_id = %d
813-
AND no_w_id = %d
818+
FROM new_orders%d
819+
WHERE no_d_id = %d
820+
AND no_w_id = %d
814821
ORDER BY no_o_id ASC LIMIT 1 FOR UPDATE`,
815822
`DELETE FROM new_orders%d
816-
WHERE no_o_id = %d
817-
AND no_d_id = %d
823+
WHERE no_o_id = %d
824+
AND no_d_id = %d
818825
AND no_w_id = %d`,
819826
`SELECT o_c_id
820-
FROM orders%d
821-
WHERE o_id = %d
822-
AND o_d_id = %d
827+
FROM orders%d
828+
WHERE o_id = %d
829+
AND o_d_id = %d
823830
AND o_w_id = %d`,
824-
`UPDATE orders%d
831+
`UPDATE orders%d
825832
SET o_carrier_id = %d
826-
WHERE o_id = %d
827-
AND o_d_id = %d
833+
WHERE o_id = %d
834+
AND o_d_id = %d
828835
AND o_w_id = %d`,
829-
`UPDATE order_line%d
836+
`UPDATE order_line%d
830837
SET ol_delivery_d = NOW()
831-
WHERE ol_o_id = %d
832-
AND ol_d_id = %d
838+
WHERE ol_o_id = %d
839+
AND ol_d_id = %d
833840
AND ol_w_id = %d`,
834841
`SELECT SUM(ol_amount) sm
835-
FROM order_line%d
836-
WHERE ol_o_id = %d
837-
AND ol_d_id = %d
842+
FROM order_line%d
843+
WHERE ol_o_id = %d
844+
AND ol_d_id = %d
838845
AND ol_w_id = %d`,
839-
`UPDATE customer%d
846+
`UPDATE customer%d
840847
SET c_balance = c_balance + %f,
841848
c_delivery_cnt = c_delivery_cnt + 1
842-
WHERE c_id = %d
843-
AND c_d_id = %d
849+
WHERE c_id = %d
850+
AND c_d_id = %d
844851
AND c_w_id = %d`,
845-
`SELECT d_next_o_id
852+
`SELECT d_next_o_id
846853
FROM district%d
847854
WHERE d_id = %d AND d_w_id= %d`,
848855
`SELECT COUNT(DISTINCT(s.s_i_id))
849856
FROM stock%d AS s
850-
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
851-
WHERE ol.ol_w_id = %d
857+
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
858+
WHERE ol.ol_w_id = %d
852859
AND ol.ol_d_id = %d
853-
AND ol.ol_o_id < %d
860+
AND ol.ol_o_id < %d
854861
AND ol.ol_o_id >= %d
855862
AND s.s_w_id= %d
856863
AND s.s_quantity < %d `,
@@ -861,7 +868,7 @@ AND ol_o_id < %d AND ol_o_id >= %d`,
861868
WHERE s_w_id = %d AND s_i_id = %d
862869
AND s_quantity < %d`,
863870
`SELECT min(no_o_id) mo
864-
FROM new_orders%d
871+
FROM new_orders%d
865872
WHERE no_w_id = %d AND no_d_id = %d`,
866873
`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 `,
867874
`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
@@ -3130,33 +3130,17 @@ func TestSelectWithUnionAll(t *testing.T) {
31303130
bv1, _ := sqltypes.BuildBindVariable([]int64{1, 2})
31313131
bv2, _ := sqltypes.BuildBindVariable([]int64{3})
31323132
sbc1WantQueries := []*querypb.BoundQuery{{
3133-
Sql: "select id from `user` where id in ::__vals",
3134-
BindVariables: map[string]*querypb.BindVariable{
3135-
"__vals": bv1,
3136-
"vtg1": bv,
3137-
"vtg2": bv,
3138-
},
3139-
}, {
3140-
Sql: "select id from `user` where id in ::__vals",
3133+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
31413134
BindVariables: map[string]*querypb.BindVariable{
31423135
"__vals": bv1,
31433136
"vtg1": bv,
3144-
"vtg2": bv,
31453137
},
31463138
}}
31473139
sbc2WantQueries := []*querypb.BoundQuery{{
3148-
Sql: "select id from `user` where id in ::__vals",
3149-
BindVariables: map[string]*querypb.BindVariable{
3150-
"__vals": bv2,
3151-
"vtg1": bv,
3152-
"vtg2": bv,
3153-
},
3154-
}, {
3155-
Sql: "select id from `user` where id in ::__vals",
3140+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
31563141
BindVariables: map[string]*querypb.BindVariable{
31573142
"__vals": bv2,
31583143
"vtg1": bv,
3159-
"vtg2": bv,
31603144
},
31613145
}}
31623146
session := &vtgatepb.Session{

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,18 @@ func gen4ValuesEqual(ctx *plancontext.PlanningContext, a, b []sqlparser.Expr) bo
533533

534534
func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) bool {
535535
switch a := a.(type) {
536+
case sqlparser.ValTuple:
537+
if b, ok := b.(sqlparser.ValTuple); ok {
538+
return gen4ValuesEqual(ctx, a, b)
539+
}
540+
541+
return false
542+
543+
case sqlparser.ListArg:
544+
if b, ok := b.(sqlparser.ListArg); ok {
545+
return a == b
546+
}
547+
536548
case *sqlparser.ColName:
537549
if b, ok := b.(*sqlparser.ColName); ok {
538550
if !a.Name.Equal(b.Name) {

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

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

149149
scatterA := tblA.RouteOpCode == engine.Scatter
150150
scatterB := tblB.RouteOpCode == engine.Scatter
151-
uniqueA := tblA.RouteOpCode == engine.EqualUnique
152-
uniqueB := tblB.RouteOpCode == engine.EqualUnique
153151

154152
switch {
155153
case scatterA:
@@ -158,7 +156,11 @@ func tryMergeUnionShardedRouting(
158156
case scatterB:
159157
return createMergedUnion(ctx, routeA, routeB, exprsA, exprsB, distinct, tblB)
160158

161-
case uniqueA && uniqueB:
159+
case tblA.RouteOpCode == engine.EqualUnique && tblB.RouteOpCode == engine.EqualUnique:
160+
fallthrough
161+
case tblA.RouteOpCode == engine.Equal && tblB.RouteOpCode == engine.Equal:
162+
fallthrough
163+
case tblA.RouteOpCode == engine.IN && tblB.RouteOpCode == engine.IN:
162164
aVdx := tblA.SelectedVindex()
163165
bVdx := tblB.SelectedVindex()
164166
aExpr := tblA.VindexExpressions()

0 commit comments

Comments
 (0)