From 32660ecfbab0888c30e6ea201a8c1a0e17ac2d31 Mon Sep 17 00:00:00 2001 From: Tpt Date: Sun, 3 Oct 2021 18:16:28 +0200 Subject: [PATCH] Use HashJoin in BGP if no shared variables Allows avoiding reading multiple times the same table --- lib/src/sparql/plan_builder.rs | 60 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/lib/src/sparql/plan_builder.rs b/lib/src/sparql/plan_builder.rs index 88637fb1..c7739d80 100644 --- a/lib/src/sparql/plan_builder.rs +++ b/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), graph_name: graph_name.clone(), }) - .reduce(|left, right| PlanNode::ForLoopJoin { - left: Box::new(left), - right: Box::new(right), - }) + .reduce(Self::new_join) .unwrap_or_else(|| PlanNode::StaticBindings { 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), graph_name: graph_name.clone(), }, - GraphPattern::Join { left, right } => { - let left = self.build_for_graph_pattern(left, variables, graph_name)?; - let right = 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::Join { left, right } => Self::new_join( + self.build_for_graph_pattern(left, variables, graph_name)?, + self.build_for_graph_pattern(right, variables, graph_name)?, + ), GraphPattern::LeftJoin { left, 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 match node { PlanNode::StaticBindings { .. } @@ -1160,13 +1160,13 @@ impl<'a> PlanBuilder<'a> { | PlanNode::PathPattern { .. } | PlanNode::ForLoopJoin { .. } => true, 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, .. } => { - self.is_fit_for_for_loop_join(child) + Self::is_fit_for_for_loop_join(child) } 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::LeftJoin { .. }