Skip to content

Commit

Permalink
Only convert join to nested loop if inner filter can be folded
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Mar 4, 2022
1 parent 813089b commit 8949677
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 13 deletions.
2 changes: 0 additions & 2 deletions MarkMpn.Sql4Cds.Engine.Tests/ExecutionPlanTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3868,7 +3868,6 @@ public void MetadataLeftJoinData()
<filter>
<condition attribute='accountid' operator='eq' value='@Cond1' />
</filter>
<order attribute='accountid' />
</entity>
</fetch>");
var contactFetch = AssertNode<FetchXmlScan>(nestedLoop1.RightSource);
Expand All @@ -3879,7 +3878,6 @@ public void MetadataLeftJoinData()
<filter>
<condition attribute='contactid' operator='eq' value='@Cond2' />
</filter>
<order attribute='contactid' />
</entity>
</fetch>");
}
Expand Down
32 changes: 21 additions & 11 deletions MarkMpn.Sql4Cds.Engine/ExecutionPlan/FoldableJoinNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,27 +322,37 @@ private bool FoldSingleRowJoinToNestedLoop(IDictionary<string, DataSource> dataS
if (leftSource.EstimatedRowsOut > 1)
return false;

// Add the filter to the inner side of the nested loop
var outerReference = $"@Cond{++_nestedLoopCount}";
var filteredRightSource = new FilterNode
{
Source = rightSource,
Filter = new BooleanComparisonExpression
{
FirstExpression = rightAttribute,
ComparisonType = BooleanComparisonType.Equals,
SecondExpression = new VariableReference { Name = outerReference }
}
};
var foldedRightSource = filteredRightSource.FoldQuery(dataSources, options, parameterTypes, hints);

// If we can't fold the filter down to the data source, there's no benefit from doing this so stick with the
// original join type
if (foldedRightSource == filteredRightSource)
return false;

var nestedLoop = new NestedLoopNode
{
JoinType = joinType,
LeftSource = leftSource,
RightSource = new FilterNode
{
Source = rightSource,
Filter = new BooleanComparisonExpression
{
FirstExpression = rightAttribute,
ComparisonType = BooleanComparisonType.Equals,
SecondExpression = new VariableReference { Name = outerReference }
}
},
RightSource = foldedRightSource,
OuterReferences = new Dictionary<string, string>
{
[leftAttr] = outerReference
}
};

// Merge joins might have added sorts already. They're not needed any longer, so remove them.
if (nestedLoop.LeftSource is SortNode leftSort)
nestedLoop.LeftSource = leftSort.Source;
else if (nestedLoop.LeftSource is FetchXmlScan leftFetch)
Expand All @@ -353,7 +363,7 @@ private bool FoldSingleRowJoinToNestedLoop(IDictionary<string, DataSource> dataS
else if (nestedLoop.RightSource is FetchXmlScan rightFetch)
rightFetch.RemoveSorts();

folded = nestedLoop.FoldQuery(dataSources, options, parameterTypes, hints);
folded = nestedLoop;
return true;
}

Expand Down

0 comments on commit 8949677

Please sign in to comment.