Skip to content

Commit

Permalink
[opt](Nereids) add where Null rule to create empty relation as where …
Browse files Browse the repository at this point in the history
…false (#38135)

explain shape plan select * from table2 where Null;
explain shape plan select * from table2 where false;
in this case, null literal can be regard as same as false literal
  • Loading branch information
LiBinfeng-01 committed Jul 31, 2024
1 parent d610a2d commit 628db9b
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
Expand All @@ -45,12 +46,13 @@ public class EliminateFilter implements RewriteRuleFactory {
@Override
public List<Rule> buildRules() {
return ImmutableList.of(logicalFilter().when(
filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance))
filter -> filter.getConjuncts().stream().anyMatch(BooleanLiteral.class::isInstance)
|| filter.getConjuncts().stream().anyMatch(NullLiteral.class::isInstance))
.thenApply(ctx -> {
LogicalFilter<Plan> filter = ctx.root;
ImmutableSet.Builder newConjuncts = ImmutableSet.builder();
for (Expression expression : filter.getConjuncts()) {
if (expression == BooleanLiteral.FALSE) {
if (expression == BooleanLiteral.FALSE || expression.isNullLiteral()) {
return new LogicalEmptyRelation(ctx.statementContext.getNextRelationId(),
filter.getOutput());
} else if (expression != BooleanLiteral.TRUE) {
Expand Down Expand Up @@ -80,7 +82,7 @@ public List<Rule> buildRules() {
Expression foldExpression =
FoldConstantRule.INSTANCE.rewrite(newExpr, context);

if (foldExpression == BooleanLiteral.FALSE) {
if (foldExpression == BooleanLiteral.FALSE || expression.isNullLiteral()) {
return new LogicalEmptyRelation(
ctx.statementContext.getNextRelationId(), filter.getOutput());
} else if (foldExpression != BooleanLiteral.TRUE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.doris.nereids.rules.rewrite;

import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
import org.apache.doris.nereids.util.LogicalPlanBuilder;
import org.apache.doris.nereids.util.MemoPatternMatchSupported;
Expand All @@ -42,6 +43,17 @@ void testEliminateFilterFalse() {
.matches(logicalEmptyRelation());
}

@Test
void testEliminateFilterNull() {
LogicalPlan filterNull = new LogicalPlanBuilder(PlanConstructor.newLogicalOlapScan(0, "t1", 0))
.filter(NullLiteral.INSTANCE)
.build();

PlanChecker.from(MemoTestUtils.createConnectContext(), filterNull)
.applyTopDown(new EliminateFilter())
.matches(logicalEmptyRelation());
}

@Test
void testEliminateFilterTrue() {
LogicalPlan filterTrue = new LogicalPlanBuilder(PlanConstructor.newLogicalOlapScan(0, "t1", 0))
Expand Down
75 changes: 75 additions & 0 deletions regression-test/data/empty_relation/eliminate_empty.out
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,81 @@ PhysicalResultSink

-- !except_empty_data --

-- !null_join --
PhysicalResultSink
--PhysicalEmptyRelation

-- !null_explain_union_empty_data --
PhysicalResultSink
--PhysicalDistribute[DistributionSpecGather]
----hashAgg[LOCAL]
------PhysicalProject
--------PhysicalOlapScan[nation]

-- !null_union_empty_data --
1

-- !null_explain_union_empty_empty --
PhysicalResultSink
--PhysicalEmptyRelation

-- !null_union_empty_empty --

-- !null_union_emtpy_onerow --
10

-- !null_explain_intersect_data_empty --
PhysicalResultSink
--PhysicalEmptyRelation

-- !null_explain_intersect_empty_data --
PhysicalResultSink
--PhysicalEmptyRelation

-- !null_explain_except_data_empty --
PhysicalResultSink
--PhysicalDistribute[DistributionSpecGather]
----PhysicalProject
------hashAgg[LOCAL]
--------PhysicalProject
----------PhysicalOlapScan[nation]

-- !null_explain_except_data_empty_data --
PhysicalResultSink
--PhysicalDistribute[DistributionSpecGather]
----PhysicalExcept
------PhysicalDistribute[DistributionSpecHash]
--------PhysicalProject
----------PhysicalOlapScan[nation]
------PhysicalDistribute[DistributionSpecHash]
--------PhysicalProject
----------filter(( not (n_nationkey = 1)))
------------PhysicalOlapScan[nation]

-- !null_except_data_empty_data --
1

-- !null_explain_except_empty_data --
PhysicalResultSink
--PhysicalEmptyRelation

-- !null_intersect_data_empty --

-- !null_intersect_empty_data --

-- !null_except_data_empty --
1

-- !null_except_empty_data --

-- !prune_partition1 --
PhysicalResultSink
--PhysicalEmptyRelation

-- !prune_partition2 --
PhysicalResultSink
--PhysicalEmptyRelation

-- !join_with_empty_child --
2 8 e v 3
4 7 at 2
Expand Down
139 changes: 138 additions & 1 deletion regression-test/suites/empty_relation/eliminate_empty.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,143 @@ suite("eliminate_empty") {
select r_regionkey from region where false except select n_nationkey from nation
"""

qt_null_join """
explain shape plan
select *
from
nation
join
(select * from region where Null) R
"""

qt_null_explain_union_empty_data """
explain shape plan
select *
from (select n_nationkey from nation union select r_regionkey from region where Null) T
"""
qt_null_union_empty_data """
select *
from (select n_nationkey from nation union select r_regionkey from region where Null) T
"""

qt_null_explain_union_empty_empty """
explain shape plan
select *
from (
select n_nationkey from nation where Null
union
select r_regionkey from region where Null
) T
"""
qt_null_union_empty_empty """
select *
from (
select n_nationkey from nation where Null
union
select r_regionkey from region where Null
) T
"""
qt_null_union_emtpy_onerow """
select *
from (
select n_nationkey from nation where Null
union
select 10
union
select 10
)T
"""

qt_null_explain_intersect_data_empty """
explain shape plan
select n_nationkey from nation intersect select r_regionkey from region where Null
"""

qt_null_explain_intersect_empty_data """
explain shape plan
select r_regionkey from region where Null intersect select n_nationkey from nation
"""

qt_null_explain_except_data_empty """
explain shape plan
select n_nationkey from nation except select r_regionkey from region where Null
"""

qt_null_explain_except_data_empty_data """
explain shape plan
select n_nationkey from nation
except
select r_regionkey from region where Null
except
select n_nationkey from nation where n_nationkey != 1;
"""

qt_null_except_data_empty_data """
select n_nationkey from nation
except
select r_regionkey from region where Null
except
select n_nationkey from nation where n_nationkey != 1;
"""

qt_null_explain_except_empty_data """
explain shape plan
select r_regionkey from region where Null except select n_nationkey from nation
"""


qt_null_intersect_data_empty """
select n_nationkey from nation intersect select r_regionkey from region where Null
"""

qt_null_intersect_empty_data """
select r_regionkey from region where Null intersect select n_nationkey from nation
"""

qt_null_except_data_empty """
select n_nationkey from nation except select r_regionkey from region where Null
"""

qt_null_except_empty_data """
select r_regionkey from region where Null except select n_nationkey from nation
"""

sql """
drop table if exists eliminate_partition_prune;
"""
sql """
CREATE TABLE `eliminate_partition_prune` (
`k1` int(11) NULL COMMENT "",
`k2` int(11) NULL COMMENT "",
`k3` int(11) NULL COMMENT ""
)
PARTITION BY RANGE(`k1`, `k2`)
(PARTITION p1 VALUES LESS THAN ("3", "1"),
PARTITION p2 VALUES [("3", "1"), ("7", "10")),
PARTITION p3 VALUES [("7", "10"), ("10", "15")))
DISTRIBUTED BY HASH(`k1`) BUCKETS 10
PROPERTIES ('replication_num' = '1');
"""


qt_prune_partition1 """
explain shape plan
select sum(k2)
from
(select * from eliminate_partition_prune where k1=100) T
group by k3;
"""
sql """
insert into eliminate_partition_prune values (7, 0, 0)
"""
qt_prune_partition2 """
explain shape plan
select sum(k2)
from
(select * from eliminate_partition_prune where k1=100) T
group by k3;
"""

sql """drop table if exists table_5_undef_partitions2_keys3"""
sql """drop table if exists table_10_undef_partitions2_keys3"""

Expand Down Expand Up @@ -179,4 +316,4 @@ suite("eliminate_empty") {
sql """drop table if exists table_5_undef_partitions2_keys3"""
sql """drop table if exists table_10_undef_partitions2_keys3"""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,6 @@ suite("test_simplify_comparison") {
contains "CAST"
}

explain {
sql "verbose select * from simple_test_table_t where a = cast(1.1 as double) and b = cast(1.1 as double) and c = cast(1.1 as double) and d = cast(1.1 as double);"
contains "a[#0] IS NULL"
contains "b[#1] IS NULL"
contains "c[#2] IS NULL"
contains "d[#3] IS NULL"
contains "AND NULL"
}

explain {
sql "verbose select * from simple_test_table_t where e = cast(1.1 as double);"
contains "CAST(e[#4] AS DOUBLE) = 1.1"
Expand Down Expand Up @@ -204,15 +195,6 @@ suite("test_simplify_comparison") {
contains "CAST"
}

explain {
sql "verbose select * from simple_test_table_t where a = 1.1 and b = 1.1 and c = 1.1 and d = 1.1;"
contains "a[#0] IS NULL"
contains "b[#1] IS NULL"
contains "c[#2] IS NULL"
contains "d[#3] IS NULL"
contains "AND NULL"
}

explain {
sql "verbose select * from simple_test_table_t where e = 1.1;"
contains "CAST(e[#4] AS DOUBLE) = 1.1"
Expand Down Expand Up @@ -272,4 +254,4 @@ suite("test_simplify_comparison") {

qt_select1 """select * from simple_test_table_t where cast(a as decimal(5,1)) = 10.0;"""
qt_select2 """select a.col1, cast(a.col1 as decimal(7,2)) col3, case when a.col1 is null then 15 when cast(a.col1 as decimal(7,2)) < -99997.99 then 18 when cast(a.col1 as decimal(7,2)) < 1.001 then 3 else -55 end col2 from (select 1 as col1) a;"""
}
}

0 comments on commit 628db9b

Please sign in to comment.