Use HashJoin in BGP if no shared variables

Allows avoiding reading multiple times the same table
pull/171/head
Tpt 3 years ago
parent 19c862228a
commit 32660ecfba
  1. 60
      lib/src/sparql/plan_builder.rs

@ -52,10 +52,7 @@ impl<'a> PlanBuilder<'a> {
object: self.pattern_value_from_term_or_variable(&triple.object, variables), object: self.pattern_value_from_term_or_variable(&triple.object, variables),
graph_name: graph_name.clone(), graph_name: graph_name.clone(),
}) })
.reduce(|left, right| PlanNode::ForLoopJoin { .reduce(Self::new_join)
left: Box::new(left),
right: Box::new(right),
})
.unwrap_or_else(|| PlanNode::StaticBindings { .unwrap_or_else(|| PlanNode::StaticBindings {
tuples: vec![EncodedTuple::with_capacity(variables.len())], tuples: vec![EncodedTuple::with_capacity(variables.len())],
}), }),
@ -69,28 +66,10 @@ impl<'a> PlanBuilder<'a> {
object: self.pattern_value_from_term_or_variable(object, variables), object: self.pattern_value_from_term_or_variable(object, variables),
graph_name: graph_name.clone(), graph_name: graph_name.clone(),
}, },
GraphPattern::Join { left, right } => { GraphPattern::Join { left, right } => Self::new_join(
let left = self.build_for_graph_pattern(left, variables, graph_name)?; self.build_for_graph_pattern(left, variables, graph_name)?,
let right = self.build_for_graph_pattern(right, variables, graph_name)?; self.build_for_graph_pattern(right, variables, graph_name)?,
if self.is_fit_for_for_loop_join(&left) ),
&& self.is_fit_for_for_loop_join(&right)
&& left
.always_bound_variables()
.intersection(&right.always_bound_variables())
.next()
.is_some()
{
PlanNode::ForLoopJoin {
left: Box::new(left),
right: Box::new(right),
}
} else {
PlanNode::HashJoin {
left: Box::new(left),
right: Box::new(right),
}
}
}
GraphPattern::LeftJoin { GraphPattern::LeftJoin {
left, left,
right, right,
@ -1152,7 +1131,28 @@ impl<'a> PlanBuilder<'a> {
} }
} }
fn is_fit_for_for_loop_join(&self, node: &PlanNode) -> bool { fn new_join(left: PlanNode, right: PlanNode) -> PlanNode {
if Self::is_fit_for_for_loop_join(&left)
&& Self::is_fit_for_for_loop_join(&right)
&& left
.always_bound_variables()
.intersection(&right.always_bound_variables())
.next()
.is_some()
{
PlanNode::ForLoopJoin {
left: Box::new(left),
right: Box::new(right),
}
} else {
PlanNode::HashJoin {
left: Box::new(left),
right: Box::new(right),
}
}
}
fn is_fit_for_for_loop_join(node: &PlanNode) -> bool {
//TODO: think more about it //TODO: think more about it
match node { match node {
PlanNode::StaticBindings { .. } PlanNode::StaticBindings { .. }
@ -1160,13 +1160,13 @@ impl<'a> PlanBuilder<'a> {
| PlanNode::PathPattern { .. } | PlanNode::PathPattern { .. }
| PlanNode::ForLoopJoin { .. } => true, | PlanNode::ForLoopJoin { .. } => true,
PlanNode::HashJoin { left, right } => { PlanNode::HashJoin { left, right } => {
self.is_fit_for_for_loop_join(left) && self.is_fit_for_for_loop_join(right) Self::is_fit_for_for_loop_join(left) && Self::is_fit_for_for_loop_join(right)
} }
PlanNode::Filter { child, .. } | PlanNode::Extend { child, .. } => { PlanNode::Filter { child, .. } | PlanNode::Extend { child, .. } => {
self.is_fit_for_for_loop_join(child) Self::is_fit_for_for_loop_join(child)
} }
PlanNode::Union { children } => { PlanNode::Union { children } => {
children.iter().all(|c| self.is_fit_for_for_loop_join(c)) children.iter().all(|c| Self::is_fit_for_for_loop_join(c))
} }
PlanNode::AntiJoin { .. } PlanNode::AntiJoin { .. }
| PlanNode::LeftJoin { .. } | PlanNode::LeftJoin { .. }

Loading…
Cancel
Save