Skip to content

Commit b651c10

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

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

@@ -326,8 +328,22 @@ func (nz *normalizer) rewriteInComparisons(node *ComparisonExpr) {
326328
Value: bval.Value,
327329
})
328330
}
329-
bvname := nz.reserved.nextUnusedVar()
330-
nz.bindVars[bvname] = bvals
331+
332+
var bvname string
333+
334+
if key, err := bvals.MarshalVT(); err != nil {
335+
bvname = nz.reserved.nextUnusedVar()
336+
nz.bindVars[bvname] = bvals
337+
} else {
338+
// Check if we can find key in tuplevals
339+
if bvname, ok = nz.tupleVals[string(key)]; !ok {
340+
bvname = nz.reserved.nextUnusedVar()
341+
}
342+
343+
nz.bindVars[bvname] = bvals
344+
nz.tupleVals[string(key)] = bvname
345+
}
346+
331347
// Modify RHS to be a list bindvar.
332348
node.Right = ListArg(bvname)
333349
}

go/vt/sqlparser/normalizer_test.go

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,13 @@ func TestNormalize(t *testing.T) {
315315
outbv: map[string]*querypb.BindVariable{
316316
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
317317
},
318+
}, {
319+
// repeated IN clause with vals
320+
in: "select * from t where v1 in (1, '2') OR v2 in (1, '2')",
321+
outstmt: "select * from t where v1 in ::bv1 or v2 in ::bv1",
322+
outbv: map[string]*querypb.BindVariable{
323+
"bv1": sqltypes.TestBindVariable([]any{1, "2"}),
324+
},
318325
}, {
319326
// NOT IN clause
320327
in: "select * from t where v1 not in (1, '2')",
@@ -729,9 +736,9 @@ JOIN warehouse%d AS w ON c_w_id=w_id
729736
WHERE w_id = %d
730737
AND c_d_id = %d
731738
AND c_id = %d`,
732-
`SELECT d_next_o_id, d_tax
733-
FROM district%d
734-
WHERE d_w_id = %d
739+
`SELECT d_next_o_id, d_tax
740+
FROM district%d
741+
WHERE d_w_id = %d
735742
AND d_id = %d FOR UPDATE`,
736743
`UPDATE district%d
737744
SET d_next_o_id = %d
@@ -741,130 +748,130 @@ WHERE d_id = %d AND d_w_id= %d`,
741748
VALUES (%d,%d,%d,%d,NOW(),%d,%d)`,
742749
`INSERT INTO new_orders%d (no_o_id, no_d_id, no_w_id)
743750
VALUES (%d,%d,%d)`,
744-
`SELECT i_price, i_name, i_data
751+
`SELECT i_price, i_name, i_data
745752
FROM item%d
746753
WHERE i_id = %d`,
747-
`SELECT s_quantity, s_data, s_dist_%s s_dist
748-
FROM stock%d
754+
`SELECT s_quantity, s_data, s_dist_%s s_dist
755+
FROM stock%d
749756
WHERE s_i_id = %d AND s_w_id= %d FOR UPDATE`,
750757
`UPDATE stock%d
751758
SET s_quantity = %d
752-
WHERE s_i_id = %d
759+
WHERE s_i_id = %d
753760
AND s_w_id= %d`,
754761
`INSERT INTO order_line%d
755762
(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)
756763
VALUES (%d,%d,%d,%d,%d,%d,%d,%d,'%s')`,
757764
`UPDATE warehouse%d
758-
SET w_ytd = w_ytd + %d
765+
SET w_ytd = w_ytd + %d
759766
WHERE w_id = %d`,
760767
`SELECT w_street_1, w_street_2, w_city, w_state, w_zip, w_name
761768
FROM warehouse%d
762769
WHERE w_id = %d`,
763-
`UPDATE district%d
764-
SET d_ytd = d_ytd + %d
765-
WHERE d_w_id = %d
770+
`UPDATE district%d
771+
SET d_ytd = d_ytd + %d
772+
WHERE d_w_id = %d
766773
AND d_id= %d`,
767-
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
774+
`SELECT d_street_1, d_street_2, d_city, d_state, d_zip, d_name
768775
FROM district%d
769-
WHERE d_w_id = %d
776+
WHERE d_w_id = %d
770777
AND d_id = %d`,
771778
`SELECT count(c_id) namecnt
772779
FROM customer%d
773-
WHERE c_w_id = %d
780+
WHERE c_w_id = %d
774781
AND c_d_id= %d
775782
AND c_last='%s'`,
776783
`SELECT c_first, c_middle, c_last, c_street_1,
777784
c_street_2, c_city, c_state, c_zip, c_phone,
778785
c_credit, c_credit_lim, c_discount, c_balance, c_ytd_payment, c_since
779786
FROM customer%d
780-
WHERE c_w_id = %d
787+
WHERE c_w_id = %d
781788
AND c_d_id= %d
782789
AND c_id=%d FOR UPDATE`,
783790
`SELECT c_data
784791
FROM customer%d
785-
WHERE c_w_id = %d
792+
WHERE c_w_id = %d
786793
AND c_d_id=%d
787794
AND c_id= %d`,
788795
`UPDATE customer%d
789796
SET c_balance=%f, c_ytd_payment=%f, c_data='%s'
790-
WHERE c_w_id = %d
797+
WHERE c_w_id = %d
791798
AND c_d_id=%d
792799
AND c_id=%d`,
793800
`UPDATE customer%d
794801
SET c_balance=%f, c_ytd_payment=%f
795-
WHERE c_w_id = %d
802+
WHERE c_w_id = %d
796803
AND c_d_id=%d
797804
AND c_id=%d`,
798805
`INSERT INTO history%d
799806
(h_c_d_id, h_c_w_id, h_c_id, h_d_id, h_w_id, h_date, h_amount, h_data)
800807
VALUES (%d,%d,%d,%d,%d,NOW(),%d,'%s')`,
801808
`SELECT count(c_id) namecnt
802809
FROM customer%d
803-
WHERE c_w_id = %d
810+
WHERE c_w_id = %d
804811
AND c_d_id= %d
805812
AND c_last='%s'`,
806813
`SELECT c_balance, c_first, c_middle, c_id
807814
FROM customer%d
808-
WHERE c_w_id = %d
815+
WHERE c_w_id = %d
809816
AND c_d_id= %d
810817
AND c_last='%s' ORDER BY c_first`,
811818
`SELECT c_balance, c_first, c_middle, c_last
812819
FROM customer%d
813-
WHERE c_w_id = %d
820+
WHERE c_w_id = %d
814821
AND c_d_id=%d
815822
AND c_id=%d`,
816823
`SELECT o_id, o_carrier_id, o_entry_d
817-
FROM orders%d
818-
WHERE o_w_id = %d
819-
AND o_d_id = %d
820-
AND o_c_id = %d
824+
FROM orders%d
825+
WHERE o_w_id = %d
826+
AND o_d_id = %d
827+
AND o_c_id = %d
821828
ORDER BY o_id DESC`,
822829
`SELECT ol_i_id, ol_supply_w_id, ol_quantity, ol_amount, ol_delivery_d
823830
FROM order_line%d WHERE ol_w_id = %d AND ol_d_id = %d AND ol_o_id = %d`,
824831
`SELECT no_o_id
825-
FROM new_orders%d
826-
WHERE no_d_id = %d
827-
AND no_w_id = %d
832+
FROM new_orders%d
833+
WHERE no_d_id = %d
834+
AND no_w_id = %d
828835
ORDER BY no_o_id ASC LIMIT 1 FOR UPDATE`,
829836
`DELETE FROM new_orders%d
830-
WHERE no_o_id = %d
831-
AND no_d_id = %d
837+
WHERE no_o_id = %d
838+
AND no_d_id = %d
832839
AND no_w_id = %d`,
833840
`SELECT o_c_id
834-
FROM orders%d
835-
WHERE o_id = %d
836-
AND o_d_id = %d
841+
FROM orders%d
842+
WHERE o_id = %d
843+
AND o_d_id = %d
837844
AND o_w_id = %d`,
838-
`UPDATE orders%d
845+
`UPDATE orders%d
839846
SET o_carrier_id = %d
840-
WHERE o_id = %d
841-
AND o_d_id = %d
847+
WHERE o_id = %d
848+
AND o_d_id = %d
842849
AND o_w_id = %d`,
843-
`UPDATE order_line%d
850+
`UPDATE order_line%d
844851
SET ol_delivery_d = NOW()
845-
WHERE ol_o_id = %d
846-
AND ol_d_id = %d
852+
WHERE ol_o_id = %d
853+
AND ol_d_id = %d
847854
AND ol_w_id = %d`,
848855
`SELECT SUM(ol_amount) sm
849-
FROM order_line%d
850-
WHERE ol_o_id = %d
851-
AND ol_d_id = %d
856+
FROM order_line%d
857+
WHERE ol_o_id = %d
858+
AND ol_d_id = %d
852859
AND ol_w_id = %d`,
853-
`UPDATE customer%d
860+
`UPDATE customer%d
854861
SET c_balance = c_balance + %f,
855862
c_delivery_cnt = c_delivery_cnt + 1
856-
WHERE c_id = %d
857-
AND c_d_id = %d
863+
WHERE c_id = %d
864+
AND c_d_id = %d
858865
AND c_w_id = %d`,
859-
`SELECT d_next_o_id
866+
`SELECT d_next_o_id
860867
FROM district%d
861868
WHERE d_id = %d AND d_w_id= %d`,
862869
`SELECT COUNT(DISTINCT(s.s_i_id))
863870
FROM stock%d AS s
864-
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
865-
WHERE ol.ol_w_id = %d
871+
JOIN order_line%d AS ol ON ol.ol_w_id=s.s_w_id AND ol.ol_i_id=s.s_i_id
872+
WHERE ol.ol_w_id = %d
866873
AND ol.ol_d_id = %d
867-
AND ol.ol_o_id < %d
874+
AND ol.ol_o_id < %d
868875
AND ol.ol_o_id >= %d
869876
AND s.s_w_id= %d
870877
AND s.s_quantity < %d `,
@@ -875,7 +882,7 @@ AND ol_o_id < %d AND ol_o_id >= %d`,
875882
WHERE s_w_id = %d AND s_i_id = %d
876883
AND s_quantity < %d`,
877884
`SELECT min(no_o_id) mo
878-
FROM new_orders%d
885+
FROM new_orders%d
879886
WHERE no_w_id = %d AND no_d_id = %d`,
880887
`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 `,
881888
`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
@@ -3124,33 +3124,17 @@ func TestSelectWithUnionAll(t *testing.T) {
31243124
bv1, _ := sqltypes.BuildBindVariable([]int64{1, 2})
31253125
bv2, _ := sqltypes.BuildBindVariable([]int64{3})
31263126
sbc1WantQueries := []*querypb.BoundQuery{{
3127-
Sql: "select id from `user` where id in ::__vals",
3128-
BindVariables: map[string]*querypb.BindVariable{
3129-
"__vals": bv1,
3130-
"vtg1": bv,
3131-
"vtg2": bv,
3132-
},
3133-
}, {
3134-
Sql: "select id from `user` where id in ::__vals",
3127+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
31353128
BindVariables: map[string]*querypb.BindVariable{
31363129
"__vals": bv1,
31373130
"vtg1": bv,
3138-
"vtg2": bv,
31393131
},
31403132
}}
31413133
sbc2WantQueries := []*querypb.BoundQuery{{
3142-
Sql: "select id from `user` where id in ::__vals",
3143-
BindVariables: map[string]*querypb.BindVariable{
3144-
"__vals": bv2,
3145-
"vtg1": bv,
3146-
"vtg2": bv,
3147-
},
3148-
}, {
3149-
Sql: "select id from `user` where id in ::__vals",
3134+
Sql: "select id from `user` where id in ::__vals union all select id from `user` where id in ::vtg1",
31503135
BindVariables: map[string]*querypb.BindVariable{
31513136
"__vals": bv2,
31523137
"vtg1": bv,
3153-
"vtg2": bv,
31543138
},
31553139
}}
31563140
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
@@ -480,6 +480,18 @@ func gen4ValuesEqual(ctx *plancontext.PlanningContext, a, b []sqlparser.Expr) bo
480480

481481
func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) bool {
482482
switch a := a.(type) {
483+
case sqlparser.ValTuple:
484+
if b, ok := b.(sqlparser.ValTuple); ok {
485+
return gen4ValuesEqual(ctx, a, b)
486+
}
487+
488+
return false
489+
490+
case sqlparser.ListArg:
491+
if b, ok := b.(sqlparser.ListArg); ok {
492+
return a == b
493+
}
494+
483495
case *sqlparser.ColName:
484496
if b, ok := b.(*sqlparser.ColName); ok {
485497
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
@@ -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)
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)