risingwave_frontend/optimizer/rule/
top_n_on_index_rule.rsuse std::collections::BTreeMap;
use risingwave_common::util::sort_util::ColumnOrder;
use super::{BoxedRule, Rule};
use crate::optimizer::plan_node::{LogicalScan, LogicalTopN, PlanTreeNodeUnary};
use crate::optimizer::property::Order;
use crate::optimizer::PlanRef;
pub struct TopNOnIndexRule {}
impl Rule for TopNOnIndexRule {
fn apply(&self, plan: PlanRef) -> Option<PlanRef> {
let logical_top_n: &LogicalTopN = plan.as_logical_top_n()?;
let logical_scan: LogicalScan = logical_top_n.input().as_logical_scan()?.to_owned();
if !logical_scan.predicate().always_true() {
return None;
}
let order = logical_top_n.topn_order();
if order.column_orders.is_empty() {
return None;
}
if let Some(p) = self.try_on_pk(logical_top_n, logical_scan.clone(), order) {
Some(p)
} else {
self.try_on_index(logical_top_n, logical_scan, order)
}
}
}
impl TopNOnIndexRule {
pub fn create() -> BoxedRule {
Box::new(TopNOnIndexRule {})
}
fn try_on_index(
&self,
logical_top_n: &LogicalTopN,
logical_scan: LogicalScan,
required_order: &Order,
) -> Option<PlanRef> {
let order_satisfied_index = logical_scan.indexes_satisfy_order(required_order);
for index in order_satisfied_index {
if let Some(index_scan) = logical_scan.to_index_scan_if_index_covered(index) {
return Some(logical_top_n.clone_with_input(index_scan.into()).into());
}
}
None
}
fn try_on_pk(
&self,
logical_top_n: &LogicalTopN,
logical_scan: LogicalScan,
order: &Order,
) -> Option<PlanRef> {
let output_col_map = logical_scan
.output_col_idx()
.iter()
.cloned()
.enumerate()
.map(|(id, col)| (col, id))
.collect::<BTreeMap<_, _>>();
let unmatched_idx = output_col_map.len();
let primary_key = logical_scan.primary_key();
let primary_key_order = Order {
column_orders: primary_key
.iter()
.map(|o| {
ColumnOrder::new(
*output_col_map
.get(&o.column_index)
.unwrap_or(&unmatched_idx),
o.order_type,
)
})
.collect::<Vec<_>>(),
};
if primary_key_order.satisfies(order) {
Some(logical_top_n.clone_with_input(logical_scan.into()).into())
} else {
None
}
}
}