-
Notifications
You must be signed in to change notification settings - Fork 574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(frontend): create mview on singleton upstream mview #4153
Changes from all commits
6128dd4
367c9d0
430e655
f1c6f36
74ae359
fe4dcc4
95d3a1d
eb8109f
6b14c11
b48cc6f
fa82839
4f6f8d7
99832bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
statement ok | ||
create table t (v int); | ||
|
||
statement ok | ||
insert into t values (666), (233), (233); | ||
|
||
# Create singleton mview | ||
statement ok | ||
create materialized view mv as select v from t order by v limit 10; | ||
|
||
statement ok | ||
create materialized view mom as select * from mv; | ||
|
||
query I | ||
select * from mv order by v; | ||
---- | ||
233 | ||
233 | ||
666 | ||
|
||
statement ok | ||
drop materialized view mom; | ||
|
||
statement ok | ||
create materialized view mvjoin as select mv1.v as vvvv from mv as mv1, mv as mv2 where mv1.v = mv2.v; | ||
|
||
query I | ||
select * from mvjoin order by vvvv; | ||
---- | ||
233 | ||
233 | ||
233 | ||
233 | ||
666 | ||
|
||
statement ok | ||
drop materialized view mvjoin; | ||
|
||
statement ok | ||
drop materialized view mv; | ||
|
||
statement ok | ||
drop table t; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,7 @@ impl BatchSeqScan { | |
} | ||
|
||
pub fn new(logical: LogicalScan, scan_ranges: Vec<ScanRange>) -> Self { | ||
// Use `Single` by default, will be updated later with `clone_with_dist`. | ||
Self::new_inner(logical, Distribution::Single, scan_ranges) | ||
} | ||
|
||
|
@@ -78,6 +79,11 @@ impl BatchSeqScan { | |
Distribution::Single | ||
} else { | ||
match self.logical.distribution_key() { | ||
// FIXME: Should be `Single` if no distribution key. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened #4164 for this. |
||
// Currently the task will be scheduled to frontend under local mode, which is | ||
// unimplemented yet. Enable this when it's done. | ||
// | ||
// Some(dist_key) if dist_key.is_empty() => Distribution::Single, | ||
Some(dist_key) => Distribution::HashShard(dist_key), | ||
None => Distribution::SomeShard, | ||
} | ||
|
@@ -130,18 +136,18 @@ impl fmt::Display for BatchSeqScan { | |
|
||
let verbose = self.base.ctx.is_explain_verbose(); | ||
|
||
if self.scan_ranges.is_empty() { | ||
write!( | ||
f, | ||
"BatchScan {{ table: {}, columns: [{}] }}", | ||
self.logical.table_name(), | ||
match verbose { | ||
true => self.logical.column_names_with_table_prefix(), | ||
false => self.logical.column_names(), | ||
} | ||
.join(", ") | ||
) | ||
} else { | ||
write!( | ||
f, | ||
"BatchScan {{ table: {}, columns: [{}]", | ||
self.logical.table_name(), | ||
match verbose { | ||
true => self.logical.column_names_with_table_prefix(), | ||
false => self.logical.column_names(), | ||
} | ||
.join(", "), | ||
)?; | ||
|
||
if !self.scan_ranges.is_empty() { | ||
let order_names = match verbose { | ||
true => self.logical.order_names_with_table_prefix(), | ||
false => self.logical.order_names(), | ||
|
@@ -161,18 +167,14 @@ impl fmt::Display for BatchSeqScan { | |
} | ||
range_strs.push(range_str.join(", ")); | ||
} | ||
write!( | ||
f, | ||
"BatchScan {{ table: {}, columns: [{}], scan_ranges: [{}] }}", | ||
self.logical.table_name(), | ||
match verbose { | ||
true => self.logical.column_names_with_table_prefix(), | ||
false => self.logical.column_names(), | ||
} | ||
.join(", "), | ||
range_strs.join(" OR ") | ||
) | ||
write!(f, ", scan_ranges: [{}]", range_strs.join(" OR "))?; | ||
} | ||
|
||
if verbose { | ||
write!(f, ", distribution: {}", self.distribution())?; | ||
} | ||
|
||
write!(f, " }}") | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,10 +101,16 @@ impl Distribution { | |
} as i32, | ||
distribution: match self { | ||
Distribution::Single => None, | ||
Distribution::HashShard(key) => Some(DistributionProst::HashInfo(HashInfo { | ||
output_count, | ||
key: key.iter().map(|num| *num as u32).collect(), | ||
})), | ||
Distribution::HashShard(key) => { | ||
assert!( | ||
!key.is_empty(), | ||
"hash key should not be empty, use `Single` instead" | ||
); | ||
Comment on lines
+105
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened #4165 for this. |
||
Some(DistributionProst::HashInfo(HashInfo { | ||
output_count, | ||
key: key.iter().map(|num| *num as u32).collect(), | ||
})) | ||
} | ||
// TODO: add round robin distribution | ||
Distribution::SomeShard => None, | ||
Distribution::Broadcast => None, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -196,11 +196,13 @@ impl StreamFragmenter { | |
// TODO: Force singleton for TopN as a workaround. We should implement two phase TopN. | ||
NodeBody::TopN(_) => current_fragment.is_singleton = true, | ||
|
||
NodeBody::Chain(ref node) => { | ||
// FIXME: workaround for single-fragment mview on singleton upstream mview. | ||
NodeBody::Chain(node) => { | ||
// memorize table id for later use | ||
state | ||
.dependent_table_ids | ||
.insert(TableId::new(node.table_id)); | ||
current_fragment.is_singleton = node.is_singleton; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, the flag There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✔️ |
||
} | ||
|
||
_ => {} | ||
|
@@ -220,8 +222,8 @@ impl StreamFragmenter { | |
return self.build_delta_join(state, current_fragment, stream_node); | ||
} else { | ||
panic!( | ||
"only inner join without non-equal condition is supported for delta joins" | ||
); | ||
"only inner join without non-equal condition is supported for delta joins" | ||
); | ||
} | ||
} | ||
} | ||
|
@@ -253,8 +255,7 @@ impl StreamFragmenter { | |
match child_node.get_node_body()? { | ||
NodeBody::Exchange(_) if child_node.input.is_empty() => { | ||
// When exchange node is generated when doing rewrites, it could be having | ||
// zero input. In this case, we won't recursively | ||
// visit its children. | ||
// zero input. In this case, we won't recursively visit its children. | ||
Ok(child_node) | ||
} | ||
// Exchange node indicates a new child fragment. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the desired way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may directly operate on the
Fragment
struct in the frontend instead of the protobuf struct, so that we may be able to directly find whether a fragment is a singleton or not instead of checking the dispatcher type.Currently, we cannot check whether
is_singleton
for the most upstream fragment since there's no exchange before it. That's why we need hacking forTopN
andChain
. 😢cc @st1page