Skip to main content

dbx_core/sql/optimizer/
subquery_unnesting.rs

1//! Rule: Subquery Unnesting
2//!
3//! 서브쿼리를 Join 연산으로 평탄화(Unnest)하여 실행 성능을 높이는 규칙.
4//! 최우선적으로 `col IN (SELECT ...)` 패턴을 파악하여 Semi-Join 또는 Inner-Join 형태로 풀어냅니다.
5
6use super::OptimizationRule;
7use crate::error::DbxResult;
8use crate::sql::planner::LogicalPlan;
9
10pub struct SubqueryUnnestingRule;
11
12impl OptimizationRule for SubqueryUnnestingRule {
13    fn name(&self) -> &str {
14        "SubqueryUnnesting"
15    }
16
17    fn apply(&self, plan: LogicalPlan) -> DbxResult<LogicalPlan> {
18        self.unnest(plan)
19    }
20}
21
22impl SubqueryUnnestingRule {
23    fn unnest(&self, plan: LogicalPlan) -> DbxResult<LogicalPlan> {
24        match plan {
25            LogicalPlan::Filter { input, predicate } => {
26                let optimized_input = self.unnest(*input)?;
27
28                // IN 서브쿼리 패턴 감지 (현재 MVP Expr 트리에서는 IN 리스트만 존재,
29                // 차후 Expr::InSubquery가 추가되면 여기에 매칭)
30                // 만약 Expr::InSubquery(col_expr, subquery_plan) 이라면
31                // LogicalPlan::Join (LeftSemi) 로 변환하는 로직 수행.
32
33                Ok(LogicalPlan::Filter {
34                    input: Box::new(optimized_input),
35                    predicate,
36                })
37            }
38            LogicalPlan::Project { input, projections } => Ok(LogicalPlan::Project {
39                input: Box::new(self.unnest(*input)?),
40                projections,
41            }),
42            LogicalPlan::Aggregate {
43                input,
44                group_by,
45                aggregates,
46                mode,
47            } => Ok(LogicalPlan::Aggregate {
48                input: Box::new(self.unnest(*input)?),
49                group_by,
50                aggregates,
51                mode,
52            }),
53            LogicalPlan::Sort { input, order_by } => Ok(LogicalPlan::Sort {
54                input: Box::new(self.unnest(*input)?),
55                order_by,
56            }),
57            LogicalPlan::Limit {
58                input,
59                count,
60                offset,
61            } => Ok(LogicalPlan::Limit {
62                input: Box::new(self.unnest(*input)?),
63                count,
64                offset,
65            }),
66            LogicalPlan::Join {
67                left,
68                right,
69                join_type,
70                on,
71            } => Ok(LogicalPlan::Join {
72                left: Box::new(self.unnest(*left)?),
73                right: Box::new(self.unnest(*right)?),
74                join_type,
75                on,
76            }),
77            other => Ok(other),
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84
85    // Unit tests will simulate Expr::InSubquery unwrapping when it's added to types.rs
86}