Skip to content

Commit 5687d61

Browse files
authored
Merge pull request #10704 from sundy-li/explain-join
feat(explain): add a simple explain join to display the join orders
2 parents a0c4019 + 7314605 commit 5687d61

File tree

7 files changed

+102
-2
lines changed

7 files changed

+102
-2
lines changed

src/query/ast/src/ast/format/ast_format.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ impl<'ast> Visitor<'ast> for AstFormatVisitor {
692692
ExplainKind::Raw => "Raw",
693693
ExplainKind::Plan => "Plan",
694694
ExplainKind::Memo(_) => "Memo",
695+
ExplainKind::JOIN => "JOIN",
695696
ExplainKind::AnalyzePlan => "Analyze",
696697
});
697698
let format_ctx = AstFormatContext::with_children(name, 1);

src/query/ast/src/ast/statements/explain.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub enum ExplainKind {
2525
Raw,
2626
Plan,
2727

28+
JOIN,
29+
2830
// Explain analyze plan
2931
AnalyzePlan,
3032
}

src/query/ast/src/ast/statements/statement.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ impl Display for Statement {
253253
ExplainKind::Raw => write!(f, " RAW")?,
254254
ExplainKind::Plan => (),
255255
ExplainKind::AnalyzePlan => write!(f, " ANALYZE")?,
256-
ExplainKind::Memo(_) => write!(f, "MEMO")?,
256+
ExplainKind::JOIN => write!(f, " JOIN")?,
257+
ExplainKind::Memo(_) => write!(f, " MEMO")?,
257258
}
258259
write!(f, " {query}")?;
259260
}

src/query/ast/src/parser/statement.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub enum CreateDatabaseOption {
5656
pub fn statement(i: Input) -> IResult<StatementMsg> {
5757
let explain = map_res(
5858
rule! {
59-
EXPLAIN ~ ( AST | SYNTAX | PIPELINE | GRAPH | FRAGMENTS | RAW | MEMO )? ~ #statement
59+
EXPLAIN ~ ( AST | SYNTAX | PIPELINE | JOIN | GRAPH | FRAGMENTS | RAW | MEMO )? ~ #statement
6060
},
6161
|(_, opt_kind, statement)| {
6262
Ok(Statement::Explain {
@@ -72,6 +72,7 @@ pub fn statement(i: Input) -> IResult<StatementMsg> {
7272
ExplainKind::Syntax(pretty_stmt)
7373
}
7474
Some(TokenKind::PIPELINE) => ExplainKind::Pipeline,
75+
Some(TokenKind::JOIN) => ExplainKind::JOIN,
7576
Some(TokenKind::GRAPH) => ExplainKind::Graph,
7677
Some(TokenKind::FRAGMENTS) => ExplainKind::Fragments,
7778
Some(TokenKind::RAW) => ExplainKind::Raw,

src/query/service/src/interpreters/interpreter_explain.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,28 @@ impl Interpreter for ExplainInterpreter {
8282
_ => self.explain_plan(&self.plan)?,
8383
},
8484

85+
ExplainKind::JOIN => match &self.plan {
86+
Plan::Query {
87+
s_expr, metadata, ..
88+
} => {
89+
let ctx = self.ctx.clone();
90+
let settings = ctx.get_settings();
91+
92+
let enable_distributed_eval_index =
93+
settings.get_enable_distributed_eval_index()?;
94+
settings.set_enable_distributed_eval_index(false)?;
95+
scopeguard::defer! {
96+
let _ = settings.set_enable_distributed_eval_index(enable_distributed_eval_index);
97+
}
98+
let mut builder = PhysicalPlanBuilder::new(metadata.clone(), ctx);
99+
let plan = builder.build(s_expr).await?;
100+
self.explain_join_order(&plan, metadata)?
101+
}
102+
_ => Err(ErrorCode::Unimplemented(
103+
"Unsupported EXPLAIN JOIN statement",
104+
))?,
105+
},
106+
85107
ExplainKind::AnalyzePlan => match &self.plan {
86108
Plan::Query {
87109
s_expr,
@@ -185,6 +207,17 @@ impl ExplainInterpreter {
185207
Ok(vec![DataBlock::new_from_columns(vec![formatted_plan])])
186208
}
187209

210+
pub fn explain_join_order(
211+
&self,
212+
plan: &PhysicalPlan,
213+
metadata: &MetadataRef,
214+
) -> Result<Vec<DataBlock>> {
215+
let result = plan.format_join(metadata)?.format_pretty()?;
216+
let line_split_result: Vec<&str> = result.lines().collect();
217+
let formatted_plan = StringType::from_data(line_split_result);
218+
Ok(vec![DataBlock::new_from_columns(vec![formatted_plan])])
219+
}
220+
188221
pub async fn explain_pipeline(
189222
&self,
190223
s_expr: SExpr,

src/query/sql/src/executor/format.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,59 @@ impl PhysicalPlan {
5555
) -> Result<FormatTreeNode<String>> {
5656
to_format_tree(self, &metadata, &prof_span_set)
5757
}
58+
59+
pub fn format_join(&self, metadata: &MetadataRef) -> Result<FormatTreeNode<String>> {
60+
match self {
61+
PhysicalPlan::TableScan(plan) => {
62+
if plan.table_index == DUMMY_TABLE_INDEX {
63+
return Ok(FormatTreeNode::with_children(
64+
format!("Scan: dummy, rows: {}", plan.source.statistics.read_rows),
65+
vec![],
66+
));
67+
}
68+
let table = metadata.read().table(plan.table_index).clone();
69+
let table_name =
70+
format!("{}.{}.{}", table.catalog(), table.database(), table.name());
71+
72+
Ok(FormatTreeNode::with_children(
73+
format!(
74+
"Scan: {}, rows: {}",
75+
table_name, plan.source.statistics.read_rows
76+
),
77+
vec![],
78+
))
79+
}
80+
PhysicalPlan::HashJoin(plan) => {
81+
let build_child = plan.build.format_join(metadata)?;
82+
let probe_child = plan.probe.format_join(metadata)?;
83+
84+
let children = vec![
85+
FormatTreeNode::with_children("Build".to_string(), vec![build_child]),
86+
FormatTreeNode::with_children("Probe".to_string(), vec![probe_child]),
87+
];
88+
89+
Ok(FormatTreeNode::with_children(
90+
format!("HashJoin: {}", plan.join_type),
91+
children,
92+
))
93+
}
94+
other => {
95+
let children = other
96+
.children()
97+
.map(|child| child.format_join(metadata))
98+
.collect::<Result<Vec<FormatTreeNode<String>>>>()?;
99+
100+
if children.len() == 1 {
101+
Ok(children[0].clone())
102+
} else {
103+
Ok(FormatTreeNode::with_children(
104+
format!("{:?}", other),
105+
children,
106+
))
107+
}
108+
}
109+
}
110+
}
58111
}
59112

60113
fn to_format_tree(

tests/sqllogictests/suites/mode/standalone/explain/join_reorder/chain.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,5 +451,14 @@ HashJoin
451451
├── push downs: [filters: [], limit: NONE]
452452
└── estimated rows: 10.00
453453

454+
query T
455+
explain join select * from t right anti join t1 on t1.a = t.a
456+
----
457+
HashJoin: LEFT ANTI
458+
├── Build
459+
│ └── Scan: default.join_reorder.t, rows: 1
460+
└── Probe
461+
└── Scan: default.join_reorder.t1, rows: 10
462+
454463
statement ok
455464
drop database join_reorder

0 commit comments

Comments
 (0)