Skip to content

Commit cc6e687

Browse files
authored
feat(optimizer): optimize always-false filter for batch (risingwavelabs#8629)
Signed-off-by: Clearlove <[email protected]>
1 parent ae99e55 commit cc6e687

File tree

9 files changed

+105
-10
lines changed

9 files changed

+105
-10
lines changed

e2e_test/batch/basic/generate_series.slt.part

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ SELECT * FROM generate_series('2'::INT,'10'::INT,'0'::INT);
8787
query I
8888
SELECT * FROM generate_series('2'::INT,'10'::INT,'-2'::INT);
8989
----
90+
91+
query I
92+
SELECT * FROM generate_series(1, 100000000, 1) where 1=0;
93+
----

e2e_test/batch/basic/join.slt.part

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,19 @@ statement ok
9292
insert into t values (1),(2),(3),(4),(5);
9393

9494
query I rowsort
95-
Select * from t join i using(x)
95+
select * from t join i using(x)
9696
----
9797
1
9898
2
9999
3
100100
4
101101
5
102102

103+
query I
104+
select * from t natural join (select * from t where 1=0);
105+
----
106+
107+
103108
statement ok
104109
drop index i;
105110

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,25 @@
201201
StreamMaterialize { columns: [id], pk_columns: [id], pk_conflict: "no check" }
202202
└─StreamExchange { dist: HashShard(idx.id) }
203203
└─StreamTableScan { table: idx, columns: [idx.id], pk: [idx.id], dist: SomeShard }
204+
- sql: |
205+
select * from generate_series(1, 10000000, 1) where Now() is null;
206+
batch_plan: |
207+
BatchValues { rows: [] }
208+
- sql: |
209+
create table t (v int);
210+
select * from t natural join (select * from t where 1=0);
211+
batch_plan: |
212+
BatchExchange { order: [], dist: Single }
213+
└─BatchHashJoin { type: Inner, predicate: t.v = t.v, output: [t.v] }
214+
├─BatchExchange { order: [], dist: HashShard(t.v) }
215+
| └─BatchScan { table: t, columns: [t.v], distribution: SomeShard }
216+
└─BatchExchange { order: [], dist: HashShard(t.v) }
217+
└─BatchValues { rows: [] }
218+
stream_plan: |
219+
StreamMaterialize { columns: [v, t._row_id(hidden), t._row_id#1(hidden)], pk_columns: [t._row_id, t._row_id#1, v], pk_conflict: "no check" }
220+
└─StreamHashJoin { type: Inner, predicate: t.v = t.v, output: [t.v, t._row_id, t._row_id] }
221+
├─StreamExchange { dist: HashShard(t.v) }
222+
| └─StreamTableScan { table: t, columns: [t.v, t._row_id], pk: [t._row_id], dist: UpstreamHashShard(t._row_id) }
223+
└─StreamExchange { dist: HashShard(t.v) }
224+
└─StreamFilter { predicate: false:Boolean }
225+
└─StreamTableScan { table: t, columns: [t.v, t._row_id], pk: [t._row_id], dist: UpstreamHashShard(t._row_id) }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"stages": {
5959
"0": {
6060
"root": {
61-
"plan_node_id": 10027,
61+
"plan_node_id": 10028,
6262
"plan_node_type": "BatchValues",
6363
"schema": [
6464
{

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,7 @@
165165
- sql: |
166166
select position(replace('1','1','2'),'123') where '12' like '%1';
167167
batch_plan: |
168-
BatchProject { exprs: [0:Int32] }
169-
└─BatchFilter { predicate: false:Boolean }
170-
└─BatchValues { rows: [[]] }
168+
BatchValues { rows: [] }
171169
- name: case searched form with else
172170
sql: |
173171
create table t (v1 int);
@@ -406,7 +404,7 @@
406404
└─LogicalProject { exprs: [Array(1:Int32) as $expr1] }
407405
└─LogicalValues { rows: [[]], schema: Schema { fields: [] } }
408406
batch_plan: |
409-
BatchProject { exprs: [Some((1:Int32 < ArrayCat($expr10035, ARRAY[2]:List { datatype: Int32 }))) as $expr1] }
407+
BatchProject { exprs: [Some((1:Int32 < ArrayCat($expr10037, ARRAY[2]:List { datatype: Int32 }))) as $expr1] }
410408
└─BatchNestedLoopJoin { type: LeftOuter, predicate: true, output: all }
411409
├─BatchValues { rows: [[]] }
412410
└─BatchValues { rows: [[ARRAY[1]:List { datatype: Int32 }]] }
@@ -429,7 +427,7 @@
429427
└─LogicalProject { exprs: [Array(1:Int32) as $expr1] }
430428
└─LogicalValues { rows: [[]], schema: Schema { fields: [] } }
431429
batch_plan: |
432-
BatchProject { exprs: [All((1:Int32 < ArrayCat($expr10035, ARRAY[2]:List { datatype: Int32 }))) as $expr1] }
430+
BatchProject { exprs: [All((1:Int32 < ArrayCat($expr10037, ARRAY[2]:List { datatype: Int32 }))) as $expr1] }
433431
└─BatchNestedLoopJoin { type: LeftOuter, predicate: true, output: all }
434432
├─BatchValues { rows: [[]] }
435433
└─BatchValues { rows: [[ARRAY[1]:List { datatype: Int32 }]] }

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
└─LogicalProject { exprs: [t.v1] }
1111
└─LogicalScan { table: t, columns: [t.v1, t.v2, t.v3, t.v4, t._row_id] }
1212
optimized_logical_plan_for_batch: |
13-
LogicalFilter { predicate: false:Boolean }
14-
└─LogicalAgg { aggs: [min(t.v1)] }
15-
└─LogicalScan { table: t, columns: [t.v1] }
13+
LogicalValues { rows: [], schema: Schema { fields: [min(t.v1):Int32] } }
1614
- name: filter should not transpose limit
1715
sql: |
1816
create table t(v1 int, v2 int, v3 int, v4 int);

src/frontend/src/optimizer/logical_optimization.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ lazy_static! {
248248
MinMaxOnIndexRule::create()],
249249
ApplyOrder::TopDown,
250250
);
251+
252+
static ref ALWAYS_FALSE_FILTER: OptimizationStage = OptimizationStage::new(
253+
"Void always-false filter's downstream",
254+
vec![AlwaysFalseFilterRule::create()],
255+
ApplyOrder::TopDown,
256+
);
251257
}
252258

253259
impl LogicalOptimizer {
@@ -440,6 +446,7 @@ impl LogicalOptimizer {
440446

441447
plan = plan.optimize_by_rules(&REWRITE_LIKE_EXPR);
442448
plan = plan.optimize_by_rules(&UNION_MERGE);
449+
plan = plan.optimize_by_rules(&ALWAYS_FALSE_FILTER);
443450

444451
plan = Self::subquery_unnesting(plan, false, explain_trace, &ctx)?;
445452

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2023 RisingWave Labs
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use risingwave_common::types::ScalarImpl;
16+
17+
use super::Rule;
18+
use crate::optimizer::plan_node::{LogicalFilter, LogicalValues};
19+
use crate::PlanRef;
20+
21+
pub struct AlwaysFalseFilterRule;
22+
23+
impl Rule for AlwaysFalseFilterRule {
24+
fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
25+
let filter: &LogicalFilter = plan.as_logical_filter()?;
26+
let always_false = filter
27+
.predicate()
28+
.conjunctions
29+
.iter()
30+
.filter_map(|e| {
31+
if e.is_const() {
32+
if let Ok(v) = e.eval_row_const() {
33+
Some(v)
34+
} else {
35+
None
36+
}
37+
} else {
38+
None
39+
}
40+
})
41+
.any(|s| s.unwrap_or(ScalarImpl::Bool(true)) == ScalarImpl::Bool(false));
42+
if always_false {
43+
Some(LogicalValues::create(
44+
vec![],
45+
filter.schema().clone(),
46+
filter.ctx(),
47+
))
48+
} else {
49+
None
50+
}
51+
}
52+
}
53+
54+
impl AlwaysFalseFilterRule {
55+
pub fn create() -> Box<dyn Rule> {
56+
Box::new(AlwaysFalseFilterRule)
57+
}
58+
}

src/frontend/src/optimizer/rule/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ mod avoid_exchange_share_rule;
9696
pub use avoid_exchange_share_rule::*;
9797
mod min_max_on_index_rule;
9898
pub use min_max_on_index_rule::*;
99+
mod always_false_filter_rule;
100+
pub use always_false_filter_rule::*;
99101

100102
mod apply_offset_rewriter;
101103
use apply_offset_rewriter::ApplyOffsetRewriter;
@@ -137,6 +139,7 @@ macro_rules! for_all_rules {
137139
, { RewriteLikeExprRule }
138140
, { AvoidExchangeShareRule }
139141
, { MinMaxOnIndexRule }
142+
, { AlwaysFalseFilterRule }
140143
, { BushyTreeJoinOrderingRule }
141144
}
142145
};

0 commit comments

Comments
 (0)