Skip to content

Commit 4380c61

Browse files
feat(optimizer): add predicate pushdown before TranslateApplyRule to reduce the domain size. (#6574)
* refactor subquery unesting * refine doc * add e2e test * refine doc * revert the rewrite of translate apply rule * fix rewrite join of translate apply * fix doc Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent a1f456c commit 4380c61

16 files changed

+395
-105
lines changed

e2e_test/batch/basic/subquery.slt.part

+30-1
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,33 @@ select a, (select count(*) from t1 where t1.a <> t.b) from t1 as t order by 1;
119119
NULL 0
120120

121121
statement ok
122-
drop table t1;
122+
drop table t1;
123+
124+
statement ok
125+
create table t1 (a int, b int);
126+
127+
statement ok
128+
create table t2 (c int, d int);
129+
130+
statement ok
131+
insert into t1 values (1, 1);
132+
133+
query IIII
134+
select * from t1 left join t2 on t1.a = t2.c where exists (select t2.d is null);
135+
----
136+
1 1 NULL NULL
137+
138+
query IIII
139+
select * from t1 left join t2 on t1.a = t2.c where exists (select t2.d where t2.d is null);
140+
----
141+
1 1 NULL NULL
142+
143+
query IIII
144+
select * from t1 left join t2 on t1.a = t2.c where exists (select t2.d where t2.d is not null);
145+
----
146+
147+
statement ok
148+
drop table t1;
149+
150+
statement ok
151+
drop table t2;

src/frontend/planner_test/tests/testdata/explain.yaml

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
LogicalProject { exprs: [1:Int32] }
1717
└─LogicalValues { rows: [[]], schema: Schema { fields: [] } }
1818
19+
Predicate Push Down:
20+
21+
LogicalProject { exprs: [1:Int32] }
22+
└─LogicalValues { rows: [[]], schema: Schema { fields: [] } }
23+
1924
Prune Columns:
2025
2126
LogicalProject { exprs: [1:Int32] }
@@ -41,7 +46,7 @@
4146
"stages": {
4247
"0": {
4348
"root": {
44-
"plan_node_id": 22,
49+
"plan_node_id": 23,
4550
"plan_node_type": "BatchProject",
4651
"schema": [
4752
{
@@ -54,7 +59,7 @@
5459
],
5560
"children": [
5661
{
57-
"plan_node_id": 20,
62+
"plan_node_id": 21,
5863
"plan_node_type": "BatchValues",
5964
"schema": [],
6065
"children": [],

src/frontend/planner_test/tests/testdata/subquery.yaml

+12-14
Original file line numberDiff line numberDiff line change
@@ -317,20 +317,18 @@
317317
└─LogicalFilter { predicate: (b.b1 = CorrelatedInputRef { index: 0, correlated_id: 1 }) }
318318
└─LogicalScan { table: b, columns: [b.b1, b.b2, b._row_id] }
319319
optimized_logical_plan: |
320-
LogicalJoin { type: Inner, on: IsNotDistinctFrom(a.a1, a.a1) AND (a.a1 = min(b.b1)), output: [a.a1, a.a2] }
320+
LogicalJoin { type: Inner, on: IsNotDistinctFrom(a.a1, a.a1) AND (a.a1 = min(b.b2)), output: [a.a1, a.a2] }
321321
├─LogicalScan { table: a, columns: [a.a1, a.a2] }
322-
└─LogicalAgg { group_key: [a.a1], aggs: [min(b.b1)] }
323-
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.a1, a.a1), output: [a.a1, b.b1] }
322+
└─LogicalAgg { group_key: [a.a1], aggs: [min(b.b2)] }
323+
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.a1, b.b1), output: [a.a1, b.b2] }
324324
├─LogicalAgg { group_key: [a.a1], aggs: [] }
325325
| └─LogicalScan { table: a, columns: [a.a1] }
326-
└─LogicalJoin { type: Inner, on: IsNotDistinctFrom(a.a1, a.a1), output: [a.a1, b.b1] }
327-
├─LogicalJoin { type: Inner, on: (b.b2 = min(b.b1)), output: [b.b1, a.a1] }
328-
| ├─LogicalScan { table: b, columns: [b.b1, b.b2] }
329-
| └─LogicalAgg { group_key: [a.a1], aggs: [min(b.b1)] }
330-
| └─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.a1, b.b1), output: [a.a1, b.b1] }
331-
| ├─LogicalAgg { group_key: [a.a1], aggs: [] }
332-
| | └─LogicalScan { table: a, columns: [a.a1] }
333-
| └─LogicalProject { exprs: [b.b1, b.b1] }
334-
| └─LogicalScan { table: b, output_columns: [b.b1], required_columns: [b1], predicate: IsNotNull(b.b1) }
335-
└─LogicalAgg { group_key: [a.a1], aggs: [] }
336-
└─LogicalScan { table: a, columns: [a.a1] }
326+
└─LogicalJoin { type: Inner, on: (b.b2 = min(b.b1)), output: [b.b1, b.b2] }
327+
├─LogicalScan { table: b, columns: [b.b1, b.b2] }
328+
└─LogicalProject { exprs: [min(b.b1)] }
329+
└─LogicalAgg { group_key: [a.a1], aggs: [min(b.b1)] }
330+
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.a1, b.b1), output: [a.a1, b.b1] }
331+
├─LogicalAgg { group_key: [a.a1], aggs: [] }
332+
| └─LogicalScan { table: a, columns: [a.a1] }
333+
└─LogicalProject { exprs: [b.b1, b.b1] }
334+
└─LogicalScan { table: b, output_columns: [b.b1], required_columns: [b1], predicate: IsNotNull(b.b1) }

src/frontend/planner_test/tests/testdata/subquery_expr_correlated.yaml

+18-18
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@
478478
└─LogicalAgg { group_key: [a.x, a.z], aggs: [count(1:Int32)] }
479479
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.x, a.x) AND IsNotDistinctFrom(a.z, a.z), output: [a.x, a.z, 1:Int32] }
480480
├─LogicalAgg { group_key: [a.x, a.z], aggs: [] }
481-
| └─LogicalScan { table: a, columns: [a.x, a.z] }
481+
| └─LogicalScan { table: a, output_columns: [a.x, a.z], required_columns: [x, z], predicate: (a.x = 3:Int32) }
482482
└─LogicalProject { exprs: [a.x, a.z, 1:Int32] }
483483
└─LogicalJoin { type: Inner, on: (b.z = a.z), output: [a.x, a.z] }
484484
├─LogicalAgg { group_key: [a.x, a.z], aggs: [] }
@@ -496,7 +496,7 @@
496496
└─LogicalAgg { group_key: [a.z], aggs: [count(1:Int32)] }
497497
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(a.z, b.z), output: [a.z, 1:Int32] }
498498
├─LogicalAgg { group_key: [a.z], aggs: [] }
499-
| └─LogicalScan { table: a, columns: [a.z] }
499+
| └─LogicalScan { table: a, output_columns: [a.z], required_columns: [z, x], predicate: (a.x = 3:Int32) }
500500
└─LogicalProject { exprs: [b.z, 1:Int32] }
501501
└─LogicalScan { table: b, output_columns: [b.z], required_columns: [z], predicate: IsNotNull(b.z) }
502502
- sql: |
@@ -561,14 +561,13 @@
561561
create table t3(x int, y int);
562562
select * from t1 where exists(select t2.x from t2 join t3 on t2.x = t3.x and t1.y = t2.y and t1.y = t3.y);
563563
optimized_logical_plan: |
564-
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t1.y), output: all }
564+
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t2.y), output: all }
565565
├─LogicalScan { table: t1, columns: [t1.x, t1.y] }
566-
└─LogicalJoin { type: Inner, on: (t2.x = t3.x) AND (t1.y = t3.y), output: [t1.y] }
567-
├─LogicalJoin { type: Inner, on: (t1.y = t2.y), output: [t1.y, t2.x] }
568-
| ├─LogicalAgg { group_key: [t1.y], aggs: [] }
569-
| | └─LogicalScan { table: t1, columns: [t1.y] }
570-
| └─LogicalScan { table: t2, columns: [t2.x, t2.y] }
571-
└─LogicalScan { table: t3, columns: [t3.x, t3.y] }
566+
└─LogicalJoin { type: Inner, on: (t2.x = t3.x) AND IsNotDistinctFrom(t2.y, t3.y), output: [t2.y] }
567+
├─LogicalProject { exprs: [t2.y, t2.x] }
568+
| └─LogicalScan { table: t2, output_columns: [t2.x, t2.y], required_columns: [x, y], predicate: IsNotNull(t2.y) }
569+
└─LogicalProject { exprs: [t3.y, t3.x] }
570+
└─LogicalScan { table: t3, output_columns: [t3.x, t3.y], required_columns: [x, y], predicate: IsNotNull(t3.y) }
572571
- sql: |
573572
create table t1(x int, y int);
574573
create table t2(x int, y int);
@@ -599,27 +598,28 @@
599598
optimized_logical_plan: |
600599
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t1.y), output: all }
601600
├─LogicalScan { table: t1, columns: [t1.x, t1.y] }
602-
└─LogicalJoin { type: LeftOuter, on: (t1.y = t2.y) AND (t2.x = t3.x) AND (t1.y = t3.y), output: [t1.y] }
601+
└─LogicalJoin { type: LeftOuter, on: (t1.y = t2.y) AND (t2.x = t3.x) AND IsNotDistinctFrom(t1.y, t3.y), output: [t1.y] }
603602
├─LogicalJoin { type: Inner, on: true, output: all }
604603
| ├─LogicalAgg { group_key: [t1.y], aggs: [] }
605604
| | └─LogicalScan { table: t1, columns: [t1.y] }
606605
| └─LogicalScan { table: t2, columns: [t2.x, t2.y] }
607-
└─LogicalScan { table: t3, columns: [t3.x, t3.y] }
606+
└─LogicalProject { exprs: [t3.y, t3.x] }
607+
└─LogicalScan { table: t3, output_columns: [t3.x, t3.y], required_columns: [x, y], predicate: IsNotNull(t3.y) }
608608
- sql: |
609609
create table t1(x int, y int);
610610
create table t2(x int, y int);
611611
create table t3(x int, y int);
612612
select * from t1 where exists(select t2.x from t2 right join t3 on t2.x = t3.x and t1.y = t2.y and t1.y = t3.y);
613613
optimized_logical_plan: |
614-
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t2.x), output: all }
614+
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t1.y), output: all }
615615
├─LogicalScan { table: t1, columns: [t1.x, t1.y] }
616-
└─LogicalJoin { type: LeftOuter, on: (t2.x = t3.x) AND (t2.x = t3.y), output: [t2.x] }
616+
└─LogicalJoin { type: LeftOuter, on: (t2.y = t3.y) AND (t2.x = t3.x) AND IsNotDistinctFrom(t2.y, t1.y), output: [t1.y] }
617617
├─LogicalJoin { type: Inner, on: true, output: all }
618-
| ├─LogicalProject { exprs: [] }
619-
| | └─LogicalAgg { group_key: [t1.y], aggs: [] }
620-
| | └─LogicalScan { table: t1, columns: [t1.y] }
618+
| ├─LogicalAgg { group_key: [t1.y], aggs: [] }
619+
| | └─LogicalScan { table: t1, columns: [t1.y] }
621620
| └─LogicalScan { table: t3, columns: [t3.x, t3.y] }
622-
└─LogicalScan { table: t2, output_columns: [t2.x], required_columns: [x, y], predicate: (t2.x = t2.y) }
621+
└─LogicalProject { exprs: [t2.y, t2.x] }
622+
└─LogicalScan { table: t2, output_columns: [t2.x, t2.y], required_columns: [x, y], predicate: IsNotNull(t2.y) }
623623
- sql: |
624624
create table t1(x int, y int);
625625
create table t2(x int, y int);
@@ -628,7 +628,7 @@
628628
optimized_logical_plan: |
629629
LogicalJoin { type: LeftSemi, on: IsNotDistinctFrom(t1.y, t1.y), output: all }
630630
├─LogicalScan { table: t1, columns: [t1.x, t1.y] }
631-
└─LogicalJoin { type: FullOuter, on: (t1.y = t2.y) AND (t2.x = t3.x) AND (t1.y = t3.y) AND IsNotDistinctFrom(t1.y, t1.y), output: [t1.y] }
631+
└─LogicalJoin { type: FullOuter, on: (t1.y = t2.y) AND (t1.y = t3.y) AND (t2.x = t3.x) AND IsNotDistinctFrom(t1.y, t1.y), output: [t1.y] }
632632
├─LogicalJoin { type: Inner, on: true, output: all }
633633
| ├─LogicalAgg { group_key: [t1.y], aggs: [] }
634634
| | └─LogicalScan { table: t1, columns: [t1.y] }

src/frontend/planner_test/tests/testdata/tpch.yaml

+24-12
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@
251251
| └─LogicalAgg { group_key: [part.p_partkey], aggs: [min(partsupp.ps_supplycost)] }
252252
| └─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(part.p_partkey, partsupp.ps_partkey), output: [part.p_partkey, partsupp.ps_supplycost] }
253253
| ├─LogicalAgg { group_key: [part.p_partkey], aggs: [] }
254-
| | └─LogicalScan { table: part, columns: [part.p_partkey] }
254+
| | └─LogicalScan { table: part, output_columns: [part.p_partkey], required_columns: [p_partkey, p_type, p_size], predicate: (part.p_size = 4:Int32) AND Like(part.p_type, '%TIN':Varchar) }
255255
| └─LogicalJoin { type: Inner, on: (nation.n_regionkey = region.r_regionkey), output: [partsupp.ps_partkey, partsupp.ps_supplycost] }
256256
| ├─LogicalJoin { type: Inner, on: (supplier.s_nationkey = nation.n_nationkey), output: [partsupp.ps_partkey, partsupp.ps_supplycost, nation.n_regionkey] }
257257
| | ├─LogicalJoin { type: Inner, on: (supplier.s_suppkey = partsupp.ps_suppkey), output: [partsupp.ps_partkey, partsupp.ps_supplycost, supplier.s_nationkey] }
@@ -287,7 +287,9 @@
287287
| └─BatchHashJoin { type: LeftOuter, predicate: part.p_partkey IS NOT DISTINCT FROM partsupp.ps_partkey, output: [part.p_partkey, partsupp.ps_supplycost] }
288288
| ├─BatchExchange { order: [], dist: HashShard(part.p_partkey) }
289289
| | └─BatchSortAgg { group_key: [part.p_partkey], aggs: [] }
290-
| | └─BatchScan { table: part, columns: [part.p_partkey], distribution: UpstreamHashShard(part.p_partkey) }
290+
| | └─BatchProject { exprs: [part.p_partkey] }
291+
| | └─BatchFilter { predicate: (part.p_size = 4:Int32) AND Like(part.p_type, '%TIN':Varchar) }
292+
| | └─BatchScan { table: part, columns: [part.p_partkey, part.p_type, part.p_size], distribution: UpstreamHashShard(part.p_partkey) }
291293
| └─BatchExchange { order: [], dist: HashShard(partsupp.ps_partkey) }
292294
| └─BatchHashJoin { type: Inner, predicate: nation.n_regionkey = region.r_regionkey, output: [partsupp.ps_partkey, partsupp.ps_supplycost] }
293295
| ├─BatchExchange { order: [], dist: HashShard(nation.n_regionkey) }
@@ -341,7 +343,9 @@
341343
| ├─StreamExchange { dist: HashShard(part.p_partkey) }
342344
| | └─StreamProject { exprs: [part.p_partkey] }
343345
| | └─StreamHashAgg { group_key: [part.p_partkey], aggs: [count] }
344-
| | └─StreamTableScan { table: part, columns: [part.p_partkey], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
346+
| | └─StreamProject { exprs: [part.p_partkey] }
347+
| | └─StreamFilter { predicate: (part.p_size = 4:Int32) AND Like(part.p_type, '%TIN':Varchar) }
348+
| | └─StreamTableScan { table: part, columns: [part.p_partkey, part.p_type, part.p_size], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
345349
| └─StreamExchange { dist: HashShard(partsupp.ps_partkey) }
346350
| └─StreamHashJoin { type: Inner, predicate: nation.n_regionkey = region.r_regionkey, output: [partsupp.ps_partkey, partsupp.ps_supplycost, partsupp.ps_suppkey, supplier.s_suppkey, nation.n_nationkey, supplier.s_nationkey, nation.n_regionkey, region.r_regionkey] }
347351
| ├─StreamExchange { dist: HashShard(nation.n_regionkey) }
@@ -437,9 +441,11 @@
437441
StreamProject { exprs: [part.p_partkey] }
438442
StreamHashAgg { group_key: [part.p_partkey], aggs: [count] }
439443
result table: 28, state tables: []
440-
Chain { table: part, columns: [part.p_partkey], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
441-
Upstream
442-
BatchPlanNode
444+
StreamProject { exprs: [part.p_partkey] }
445+
StreamFilter { predicate: (part.p_size = 4:Int32) AND Like(part.p_type, '%TIN':Varchar) }
446+
Chain { table: part, columns: [part.p_partkey, part.p_type, part.p_size], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
447+
Upstream
448+
BatchPlanNode
443449
444450
Fragment 11
445451
StreamHashJoin { type: Inner, predicate: nation.n_regionkey = region.r_regionkey, output: [partsupp.ps_partkey, partsupp.ps_supplycost, partsupp.ps_suppkey, supplier.s_suppkey, nation.n_nationkey, supplier.s_nationkey, nation.n_regionkey, region.r_regionkey] }
@@ -2907,7 +2913,7 @@
29072913
└─LogicalAgg { group_key: [part.p_partkey], aggs: [sum(lineitem.l_quantity), count(lineitem.l_quantity)] }
29082914
└─LogicalJoin { type: LeftOuter, on: IsNotDistinctFrom(part.p_partkey, lineitem.l_partkey), output: [part.p_partkey, lineitem.l_quantity] }
29092915
├─LogicalAgg { group_key: [part.p_partkey], aggs: [] }
2910-
| └─LogicalScan { table: part, columns: [part.p_partkey] }
2916+
| └─LogicalScan { table: part, output_columns: [part.p_partkey], required_columns: [p_partkey, p_brand, p_container], predicate: (part.p_brand = 'Brand#13':Varchar) AND (part.p_container = 'JUMBO PKG':Varchar) }
29112917
└─LogicalScan { table: lineitem, output_columns: [lineitem.l_partkey, lineitem.l_quantity], required_columns: [l_partkey, l_quantity], predicate: IsNotNull(lineitem.l_partkey) }
29122918
batch_plan: |
29132919
BatchProject { exprs: [RoundDigit((sum(sum(lineitem.l_extendedprice)) / 7.0:Decimal), 16:Int32)] }
@@ -2930,7 +2936,9 @@
29302936
└─BatchHashJoin { type: LeftOuter, predicate: part.p_partkey IS NOT DISTINCT FROM lineitem.l_partkey, output: [part.p_partkey, lineitem.l_quantity] }
29312937
├─BatchExchange { order: [], dist: HashShard(part.p_partkey) }
29322938
| └─BatchSortAgg { group_key: [part.p_partkey], aggs: [] }
2933-
| └─BatchScan { table: part, columns: [part.p_partkey], distribution: UpstreamHashShard(part.p_partkey) }
2939+
| └─BatchProject { exprs: [part.p_partkey] }
2940+
| └─BatchFilter { predicate: (part.p_brand = 'Brand#13':Varchar) AND (part.p_container = 'JUMBO PKG':Varchar) }
2941+
| └─BatchScan { table: part, columns: [part.p_partkey, part.p_brand, part.p_container], distribution: UpstreamHashShard(part.p_partkey) }
29342942
└─BatchExchange { order: [], dist: HashShard(lineitem.l_partkey) }
29352943
└─BatchFilter { predicate: IsNotNull(lineitem.l_partkey) }
29362944
└─BatchScan { table: lineitem, columns: [lineitem.l_partkey, lineitem.l_quantity], distribution: SomeShard }
@@ -2957,7 +2965,9 @@
29572965
├─StreamExchange { dist: HashShard(part.p_partkey) }
29582966
| └─StreamProject { exprs: [part.p_partkey] }
29592967
| └─StreamHashAgg { group_key: [part.p_partkey], aggs: [count] }
2960-
| └─StreamTableScan { table: part, columns: [part.p_partkey], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
2968+
| └─StreamProject { exprs: [part.p_partkey] }
2969+
| └─StreamFilter { predicate: (part.p_brand = 'Brand#13':Varchar) AND (part.p_container = 'JUMBO PKG':Varchar) }
2970+
| └─StreamTableScan { table: part, columns: [part.p_partkey, part.p_brand, part.p_container], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
29612971
└─StreamExchange { dist: HashShard(lineitem.l_partkey) }
29622972
└─StreamFilter { predicate: IsNotNull(lineitem.l_partkey) }
29632973
└─StreamTableScan { table: lineitem, columns: [lineitem.l_partkey, lineitem.l_quantity, lineitem.l_orderkey, lineitem.l_linenumber], pk: [lineitem.l_orderkey, lineitem.l_linenumber], dist: UpstreamHashShard(lineitem.l_orderkey, lineitem.l_linenumber) }
@@ -3007,9 +3017,11 @@
30073017
StreamProject { exprs: [part.p_partkey] }
30083018
StreamHashAgg { group_key: [part.p_partkey], aggs: [count] }
30093019
result table: 14, state tables: []
3010-
Chain { table: part, columns: [part.p_partkey], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
3011-
Upstream
3012-
BatchPlanNode
3020+
StreamProject { exprs: [part.p_partkey] }
3021+
StreamFilter { predicate: (part.p_brand = 'Brand#13':Varchar) AND (part.p_container = 'JUMBO PKG':Varchar) }
3022+
Chain { table: part, columns: [part.p_partkey, part.p_brand, part.p_container], pk: [part.p_partkey], dist: UpstreamHashShard(part.p_partkey) }
3023+
Upstream
3024+
BatchPlanNode
30133025
30143026
Fragment 6
30153027
StreamFilter { predicate: IsNotNull(lineitem.l_partkey) }

src/frontend/src/optimizer/mod.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ impl PlanRoot {
204204
.into());
205205
}
206206

207+
// Predicate push down before translate apply, because we need to calculate the domain
208+
// and predicate push down can reduce the size of domain.
209+
plan = plan.predicate_pushdown(Condition::true_cond());
210+
if explain_trace {
211+
ctx.trace("Predicate Push Down:");
212+
ctx.trace(plan.explain_to_string().unwrap());
213+
}
214+
207215
// General Unnesting.
208216
// Translate Apply, push Apply down the plan and finally replace Apply with regular inner
209217
// join.
@@ -217,10 +225,10 @@ impl PlanRoot {
217225
plan,
218226
"General Unnesting(Push Down Apply)".to_string(),
219227
vec![
220-
ApplyAggRule::create(),
221-
ApplyFilterRule::create(),
222-
ApplyProjRule::create(),
223-
ApplyJoinRule::create(),
228+
ApplyAggTransposeRule::create(),
229+
ApplyFilterTransposeRule::create(),
230+
ApplyProjectTransposeRule::create(),
231+
ApplyJoinTransposeRule::create(),
224232
ApplyScanRule::create(),
225233
],
226234
ApplyOrder::TopDown,

0 commit comments

Comments
 (0)