diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index 657189f931..093dbc28b3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -262,9 +262,10 @@ public enum RuleType {
PUSH_DOWN_TOP_N_THROUGH_PROJECT_WINDOW(RuleTypeClass.REWRITE),
PUSH_DOWN_TOP_N_THROUGH_WINDOW(RuleTypeClass.REWRITE),
PUSH_DOWN_TOP_N_THROUGH_UNION(RuleTypeClass.REWRITE),
+ PUSH_DOWN_TOP_N_LIMIT_THROUGH_UNION(RuleTypeClass.REWRITE),
// limit distinct push down
- PUSH_LIMIT_DISTINCT_THROUGH_JOIN(RuleTypeClass.REWRITE),
- PUSH_LIMIT_DISTINCT_THROUGH_PROJECT_JOIN(RuleTypeClass.REWRITE),
+ PUSH_DOWN_LIMIT_DISTINCT_THROUGH_JOIN(RuleTypeClass.REWRITE),
+ PUSH_DOWN_LIMIT_DISTINCT_THROUGH_PROJECT_JOIN(RuleTypeClass.REWRITE),
// adjust nullable
ADJUST_NULLABLE(RuleTypeClass.REWRITE),
ADJUST_CONJUNCTS_RETURN_TYPE(RuleTypeClass.REWRITE),
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownLimitDistinctThroughJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownLimitDistinctThroughJoin.java
index 9ba73c7ed8..21f777204b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownLimitDistinctThroughJoin.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownLimitDistinctThroughJoin.java
@@ -52,7 +52,7 @@ public class PushDownLimitDistinctThroughJoin implements RewriteRuleFactory {
}
return limit.withChildren(agg.withChildren(newJoin));
})
- .toRule(RuleType.PUSH_LIMIT_DISTINCT_THROUGH_JOIN),
+ .toRule(RuleType.PUSH_DOWN_LIMIT_DISTINCT_THROUGH_JOIN),
// limit -> distinct -> project -> join
logicalLimit(logicalAggregate(logicalProject(logicalJoin()).when(LogicalProject::isAllSlots))
@@ -67,7 +67,7 @@ public class PushDownLimitDistinctThroughJoin implements RewriteRuleFactory {
return null;
}
return limit.withChildren(agg.withChildren(project.withChildren(newJoin)));
- }).toRule(RuleType.PUSH_LIMIT_DISTINCT_THROUGH_JOIN)
+ }).toRule(RuleType.PUSH_DOWN_LIMIT_DISTINCT_THROUGH_PROJECT_JOIN)
);
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownTopNDistinctThroughUnion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownTopNDistinctThroughUnion.java
new file mode 100644
index 0000000000..15023cb514
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushDownTopNDistinctThroughUnion.java
@@ -0,0 +1,91 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.rewrite;
+
+import org.apache.doris.nereids.properties.OrderKey;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier;
+import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalTopN;
+import org.apache.doris.nereids.trees.plans.logical.LogicalUnion;
+import org.apache.doris.nereids.util.ExpressionUtils;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * TopN-Distinct
+ * -> Union All
+ * -> child plan1
+ * -> child plan2
+ * -> child plan3
+ *
+ * rewritten to
+ *
+ * -> Union All
+ * -> TopN-Distinct
+ * -> child plan1
+ * -> TopN-Distinct
+ * -> child plan2
+ * -> TopN-Distinct
+ * -> child plan3
+ *
+ */
+public class PushDownTopNDistinctThroughUnion implements RewriteRuleFactory {
+
+ @Override
+ public List buildRules() {
+ return ImmutableList.of(
+ logicalTopN(logicalAggregate(logicalUnion().when(union -> union.getQualifier() == Qualifier.ALL))
+ .when(agg -> agg.isDistinct()))
+ .then(topN -> {
+ LogicalAggregate agg = topN.child();
+ LogicalUnion union = agg.child();
+ List newChildren = new ArrayList<>();
+ for (Plan child : union.children()) {
+ Map replaceMap = new HashMap<>();
+ for (int i = 0; i < union.getOutputs().size(); ++i) {
+ NamedExpression output = union.getOutputs().get(i);
+ replaceMap.put(output, child.getOutput().get(i));
+ }
+
+ List orderKeys = topN.getOrderKeys().stream()
+ .map(orderKey -> orderKey.withExpression(
+ ExpressionUtils.replace(orderKey.getExpr(), replaceMap)))
+ .collect(ImmutableList.toImmutableList());
+ newChildren.add(
+ new LogicalTopN<>(orderKeys, topN.getLimit() + topN.getOffset(), 0, child));
+ }
+ if (union.children().equals(newChildren)) {
+ return null;
+ }
+ return topN.withChildren(agg.withChildren(union.withChildren(newChildren)));
+ })
+ .toRule(RuleType.PUSH_DOWN_TOP_N_THROUGH_UNION)
+ );
+ }
+}
diff --git a/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.out b/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.out
new file mode 100644
index 0000000000..02a947642c
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.out
@@ -0,0 +1,157 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !push_down_topn_through_union --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_conditions --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------filter((t1.score > 10))
+--------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------filter((t2.name = 'Test'))
+--------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------filter((t3.id < 5))
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_order_by --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_nested_union --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_after_join --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------hashJoin[INNER_JOIN] hashCondition=((t1.id = t2.id)) otherCondition=()
+----------------------PhysicalProject
+------------------------PhysicalOlapScan[t]
+----------------------PhysicalProject
+------------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_different_projections --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_subquery --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------filter((t.score > 20))
+----------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_limit --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------PhysicalLimit[GLOBAL]
+--------------------PhysicalDistribute
+----------------------PhysicalLimit[LOCAL]
+------------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------PhysicalLimit[GLOBAL]
+--------------------PhysicalDistribute
+----------------------PhysicalLimit[LOCAL]
+------------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_complex_conditions --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------hashAgg[GLOBAL]
+----------PhysicalDistribute
+------------hashAgg[LOCAL]
+--------------PhysicalUnion
+----------------PhysicalDistribute
+------------------filter((t1.name = 'Test') and (t1.score > 10))
+--------------------PhysicalOlapScan[t]
+----------------PhysicalDistribute
+------------------filter((t2.id < 5) and (t2.score < 20))
+--------------------PhysicalOlapScan[t]
+
diff --git a/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.out b/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.out
new file mode 100644
index 0000000000..9c20ca80d5
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.out
@@ -0,0 +1,194 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !push_down_topn_through_union --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_conditions --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------filter((t1.score > 10))
+--------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------filter((t2.name = 'Test'))
+--------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------filter((t3.id < 5))
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_order_by --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_nested_union --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_after_join --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------hashJoin[INNER_JOIN] hashCondition=((t1.id = t2.id)) otherCondition=()
+----------------------PhysicalProject
+------------------------PhysicalOlapScan[t] apply RFs: RF0
+----------------------PhysicalProject
+------------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_different_projections --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_subquery --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------filter((t.score > 20))
+----------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------PhysicalProject
+--------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_with_limit --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalTopN[LOCAL_SORT]
+----------------PhysicalLimit[GLOBAL]
+------------------PhysicalDistribute
+--------------------PhysicalLimit[LOCAL]
+----------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalTopN[LOCAL_SORT]
+----------------PhysicalLimit[GLOBAL]
+------------------PhysicalDistribute
+--------------------PhysicalLimit[LOCAL]
+----------------------PhysicalOlapScan[t]
+
+-- !push_down_topn_union_complex_conditions --
+PhysicalResultSink
+--PhysicalTopN[MERGE_SORT]
+----PhysicalDistribute
+------PhysicalTopN[LOCAL_SORT]
+--------PhysicalUnion
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------filter((t1.name = 'Test') and (t1.score > 10))
+--------------------PhysicalOlapScan[t]
+----------PhysicalDistribute
+------------PhysicalTopN[MERGE_SORT]
+--------------PhysicalDistribute
+----------------PhysicalTopN[LOCAL_SORT]
+------------------filter((t2.id < 5) and (t2.score < 20))
+--------------------PhysicalOlapScan[t]
+
diff --git a/regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.groovy b/regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.groovy
new file mode 100644
index 0000000000..2d8af0ee7e
--- /dev/null
+++ b/regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_distinct_through_union.groovy
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("push_down_top_n_through_union") {
+ sql "SET enable_nereids_planner=true"
+ sql "SET enable_fallback_to_original_planner=false"
+
+ sql """
+ DROP TABLE IF EXISTS t1;
+ """
+ sql """
+ DROP TABLE IF EXISTS t2;
+ """
+ sql """
+ DROP TABLE IF EXISTS t3;
+ """
+ sql """
+ DROP TABLE IF EXISTS t4;
+ """
+
+ sql """
+ CREATE TABLE IF NOT EXISTS t(
+ `id` int(32) NULL,
+ `score` int(64) NULL,
+ `name` varchar(64) NULL
+ ) ENGINE = OLAP
+ DISTRIBUTED BY HASH(id) BUCKETS 4
+ PROPERTIES (
+ "replication_allocation" = "tag.location.default: 1"
+ );
+ """
+
+ qt_push_down_topn_through_union """
+ explain shape plan select * from (select * from t t1 union select * from t t2) t order by id limit 10;
+ """
+
+ qt_push_down_topn_union_with_conditions """
+ explain shape plan select * from (select * from t t1 where t1.score > 10 union select * from t t2 where t2.name = 'Test' union select * from t t3 where t3.id < 5) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_with_order_by """
+ explain shape plan select * from (select * from t t1 union select * from t t2 union select * from t t3 order by score) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_nested_union """
+ explain shape plan select * from ((select * from t t1 union select * from t t2) union (select * from t t3 union select * from t t4)) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_after_join """
+ explain shape plan select * from (select t1.id from t t1 join t t2 on t1.id = t2.id union select id from t t3) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_different_projections """
+ explain shape plan select * from (select id from t t1 union select name from t t2) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_with_subquery """
+ explain shape plan select * from (select id from (select * from t where score > 20) t1 union select id from t t2) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_with_limit """
+ explain shape plan select * from (select * from t t1 limit 5 union select * from t t2 limit 5) sub order by id limit 10;
+ """
+
+ qt_push_down_topn_union_complex_conditions """
+ explain shape plan select * from (select * from t t1 where t1.score > 10 and t1.name = 'Test' union select * from t t2 where t2.id < 5 and t2.score < 20) sub order by id limit 10;
+ """
+}
\ No newline at end of file
diff --git a/regression-test/suites/nereids_rules_p0/push_down_topn/push_down_topn_through_union.groovy b/regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.groovy
similarity index 98%
rename from regression-test/suites/nereids_rules_p0/push_down_topn/push_down_topn_through_union.groovy
rename to regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.groovy
index afc26a51cf..336581e232 100644
--- a/regression-test/suites/nereids_rules_p0/push_down_topn/push_down_topn_through_union.groovy
+++ b/regression-test/suites/nereids_rules_p0/push_down_top_n/push_down_top_n_through_union.groovy
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-suite("push_down_topn_through_union") {
+suite("push_down_top_n_through_union") {
sql "SET enable_nereids_planner=true"
sql "SET enable_fallback_to_original_planner=false"